214 lines
		
	
	
		
			5.0 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			214 lines
		
	
	
		
			5.0 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/*
 | 
						|
 * 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/bsl11.
 | 
						|
 *
 | 
						|
 * Change Date: 2020-01-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 <iostream>
 | 
						|
#include <string>
 | 
						|
#include <vector>
 | 
						|
#include "testconnections.h"
 | 
						|
 | 
						|
using namespace std;
 | 
						|
 | 
						|
namespace
 | 
						|
{
 | 
						|
 | 
						|
void drop(TestConnections& test)
 | 
						|
{
 | 
						|
    MYSQL* pMysql = test.maxscales->conn_rwsplit[0];
 | 
						|
 | 
						|
    string stmt("DROP TABLE IF EXISTS cache_test");
 | 
						|
 | 
						|
    cout << stmt << endl;
 | 
						|
    test.try_query(pMysql, stmt.c_str());
 | 
						|
}
 | 
						|
 | 
						|
void create(TestConnections& test)
 | 
						|
{
 | 
						|
    drop(test);
 | 
						|
 | 
						|
    MYSQL* pMysql = test.maxscales->conn_rwsplit[0];
 | 
						|
 | 
						|
    string stmt("CREATE TABLE cache_test (a INT)");
 | 
						|
 | 
						|
    cout << stmt << endl;
 | 
						|
    test.try_query(pMysql, stmt.c_str());
 | 
						|
}
 | 
						|
 | 
						|
void insert(TestConnections& test)
 | 
						|
{
 | 
						|
    MYSQL* pMysql = test.maxscales->conn_rwsplit[0];
 | 
						|
 | 
						|
    string stmt("INSERT INTO cache_test VALUES (1)");
 | 
						|
 | 
						|
    cout << stmt << endl;
 | 
						|
    test.try_query(pMysql, stmt.c_str());
 | 
						|
}
 | 
						|
 | 
						|
void update(TestConnections& test, int value)
 | 
						|
{
 | 
						|
    MYSQL* pMysql = test.maxscales->conn_rwsplit[0];
 | 
						|
 | 
						|
    string stmt("UPDATE cache_test SET a=");
 | 
						|
    stmt += std::to_string(value);
 | 
						|
 | 
						|
    cout << stmt << endl;
 | 
						|
    test.try_query(pMysql, stmt.c_str());
 | 
						|
}
 | 
						|
 | 
						|
void select(TestConnections& test, int* pValue)
 | 
						|
{
 | 
						|
    MYSQL* pMysql = test.maxscales->conn_rwsplit[0];
 | 
						|
 | 
						|
    string stmt("SELECT * FROM cache_test");
 | 
						|
 | 
						|
    cout << stmt << endl;
 | 
						|
 | 
						|
    if (mysql_query(pMysql, stmt.c_str()) == 0)
 | 
						|
    {
 | 
						|
        if (mysql_field_count(pMysql) != 0)
 | 
						|
        {
 | 
						|
            size_t nRows = 0;
 | 
						|
 | 
						|
            do
 | 
						|
            {
 | 
						|
                MYSQL_RES* pRes = mysql_store_result(pMysql);
 | 
						|
                MYSQL_ROW row = mysql_fetch_row(pRes);
 | 
						|
                *pValue = atoi(row[0]);
 | 
						|
                mysql_free_result(pRes);
 | 
						|
                ++nRows;
 | 
						|
            }
 | 
						|
            while (mysql_next_result(pMysql) == 0);
 | 
						|
 | 
						|
            test.assert(nRows == 1, "Unexpected number of rows: %u", nRows);
 | 
						|
        }
 | 
						|
    }
 | 
						|
    else
 | 
						|
    {
 | 
						|
        test.assert(false, "SELECT failed.");
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
namespace Cache
 | 
						|
{
 | 
						|
 | 
						|
enum What
 | 
						|
{
 | 
						|
    POPULATE,
 | 
						|
    USE
 | 
						|
};
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
void set(TestConnections& test, Cache::What what, bool value)
 | 
						|
{
 | 
						|
    MYSQL* pMysql = test.maxscales->conn_rwsplit[0];
 | 
						|
 | 
						|
    string stmt("SET @maxscale.cache.");
 | 
						|
    stmt += ((what == Cache::POPULATE) ? "populate" : "use");
 | 
						|
    stmt += "=";
 | 
						|
    stmt += (value ? "true" : "false");
 | 
						|
 | 
						|
    cout << stmt << endl;
 | 
						|
    test.try_query(pMysql, stmt.c_str());
 | 
						|
}
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
namespace
 | 
						|
{
 | 
						|
 | 
						|
void init(TestConnections& test)
 | 
						|
{
 | 
						|
    create(test);
 | 
						|
    insert(test);
 | 
						|
}
 | 
						|
 | 
						|
void run(TestConnections& test)
 | 
						|
{
 | 
						|
    init(test);
 | 
						|
    int value;
 | 
						|
 | 
						|
    // Let's populate the cache.
 | 
						|
    set(test, Cache::POPULATE, true);
 | 
						|
    set(test, Cache::USE, false);
 | 
						|
    select(test, &value);
 | 
						|
    test.assert(value == 1, "Initial value was not 1.");
 | 
						|
 | 
						|
    // And update the real value.
 | 
						|
    update(test, 2); // Now the cache contains 1 and the db 2.
 | 
						|
 | 
						|
    // With @maxscale.cache.use==false we should get the updated value.
 | 
						|
    set(test, Cache::POPULATE, false);
 | 
						|
    set(test, Cache::USE, false);
 | 
						|
    select(test, &value);
 | 
						|
    test.assert(value == 2, "The value received was not the latest one.");
 | 
						|
 | 
						|
    // With @maxscale.cache.use==true we should get the old one, since
 | 
						|
    // it was not updated above as @maxscale.cache.populate==false.
 | 
						|
    set(test, Cache::POPULATE, false);
 | 
						|
    set(test, Cache::USE, true);
 | 
						|
    select(test, &value);
 | 
						|
    test.assert(value == 1, "The value received was not the populated one.");
 | 
						|
 | 
						|
    // The hard_ttl is 8, so we sleep(10) seconds to ensure that TTL has passed.
 | 
						|
    cout << "Sleeping 10 seconds." << endl;
 | 
						|
    sleep(10);
 | 
						|
 | 
						|
    // With @maxscale.cache.use==true we should now get the latest value.
 | 
						|
    // The value in the cache is stale, so it will be updated even if
 | 
						|
    // @maxscale.cache.populate==false.
 | 
						|
    set(test, Cache::POPULATE, false);
 | 
						|
    set(test, Cache::USE, true);
 | 
						|
    select(test, &value);
 | 
						|
    test.assert(value == 2, "The cache was not updated even if TTL was passed.");
 | 
						|
 | 
						|
    // Let's update again
 | 
						|
    update(test, 3);
 | 
						|
 | 
						|
    // And fetch again. Should still be 2, as the item in the cache is not stale.
 | 
						|
    set(test, Cache::POPULATE, false);
 | 
						|
    set(test, Cache::USE, true);
 | 
						|
    select(test, &value);
 | 
						|
    test.assert(value == 2, "New value %d, although the value in the cache is not stale.", value);
 | 
						|
 | 
						|
    // Force an update.
 | 
						|
    set(test, Cache::POPULATE, true);
 | 
						|
    set(test, Cache::USE, false);
 | 
						|
    select(test, &value);
 | 
						|
    test.assert(value == 3, "Did not get new value.");
 | 
						|
 | 
						|
    // And check that the cache indeed was updated, but update the DB first.
 | 
						|
    update(test, 4);
 | 
						|
 | 
						|
    set(test, Cache::POPULATE, false);
 | 
						|
    set(test, Cache::USE, true);
 | 
						|
    select(test, &value);
 | 
						|
    test.assert(value == 3, "Got a newer value than expected.");
 | 
						|
}
 | 
						|
 | 
						|
}
 | 
						|
 | 
						|
int main(int argc, char* argv[])
 | 
						|
{
 | 
						|
    std::ios::sync_with_stdio(true);
 | 
						|
 | 
						|
    TestConnections test(argc, argv);
 | 
						|
 | 
						|
    if (test.maxscales->connect_rwsplit() == 0)
 | 
						|
    {
 | 
						|
        run(test);
 | 
						|
    }
 | 
						|
 | 
						|
    return test.global_result;
 | 
						|
}
 |