## Au-dela du TTL : gestionnaire de stockage défini par l'utilisateur

Le plugin de mise en cache de requête supporte l'utilisation d'un gestionnaire de stockage défini par l'utilisateur. Ce type de gestionnaire peut utilisé arbitrairement un algorithme complexe d'invalidation, et supporte le stockage sur divers médias.

Tous les gestionnaires de stockage définis par l'utilisateur doivent fournie une certaine interface. Les fonctions du gestionnaire de stocké défini par l'utilisateur seront appelées par le coeur du plugin de mise en cache. L'interface nécessaire consiste en 7 fonctions publiques. Le gestionnaire de stockage défini par l'utilisateur peut être écrit de façon procédurale ou orientée objet.

Exemple #1 Utilisation d'un gestionnaire de stockage défini par l'utilisateur

`<?php
/* Activation de la mise en cache de toutes les requêtes par défaut */
ini_set("mysqlnd_qc.cache_by_default", 1);
/* Fonctions composant le gestionnaire de stockage défini par l'utilisateur, de façon procédurale */
$__cache = array();
function get_hash($host_info, $port, $user, $db, $query) {
global $__cache;
printf("\t%s(%d)\n", __FUNCTION__, func_num_args());
return md5(sprintf("%s%s%s%s%s", $host_info, $port, $user, $db, $query));
}
function find_query_in_cache($key) {
global $__cache;
printf("\t%s(%d)\n", __FUNCTION__, func_num_args());
if (isset($__cache[$key])) {
$tmp = $__cache[$key];
if ($tmp["valid_until"] < time()) {
unset($__cache[$key]);
$ret = NULL;
} else {
$ret = $__cache[$key]["data"];
}
} else {
$ret = NULL;
}
return $ret;
}
function return_to_cache($key) {
/*
Appelé lors de la récupération d'une entrée du cache après que les données mises en
cache ne soient traitées ; peut être utilisé pour le comptage des références
*/
printf("\t%s(%d)\n", __FUNCTION__, func_num_args());
}
function add_query_to_cache_if_not_exists($key, $data, $ttl, $run_time, $store_time, $row_count) {
global $__cache;
printf("\t%s(%d)\n", __FUNCTION__, func_num_args());
$__cache[$key] = array(
"data" => $data,
"row_count" => $row_count,
"valid_until" => time() + $ttl,
"hits" => 0,
"run_time" => $run_time,
"store_time" => $store_time,
"cached_run_times" => array(),
"cached_store_times" => array(),
);
return TRUE;
}
function query_is_select($query) {
printf("\t%s('%s'): ", __FUNCTION__, $query);
$ret = FALSE;
if (stristr($query, "SELECT") !== FALSE) {
/* Mise en cache pour 5 secondes */
$ret = 5;
}
printf("%s\n", (FALSE === $ret) ? "FALSE" : $ret);
return $ret;
}
function update_query_run_time_stats($key, $run_time, $store_time) {
global $__cache;
printf("\t%s(%d)\n", __FUNCTION__, func_num_args());
if (isset($__cache[$key])) {
$__cache[$key]['hits']++;
$__cache[$key]["cached_run_times"][] = $run_time;
$__cache[$key]["cached_store_times"][] = $store_time;
}
}
function get_stats($key = NULL) {
global $__cache;
printf("\t%s(%d)\n", __FUNCTION__, func_num_args());
if ($key && isset($__cache[$key])) {
$stats = $__cache[$key];
} else {
$stats = array();
foreach ($__cache as $key => $details) {
$stats[$key] = array(
'hits' => $details['hits'],
'bytes' => strlen($details['data']),
'uncached_run_time' => $details['run_time'],
'cached_run_time' => (count($details['cached_run_times']))
? array_sum($details['cached_run_times']) / count($details['cached_run_times'])
: 0,
);
}
}
return $stats;
}
function clear_cache() {
global $__cache;
printf("\t%s(%d)\n", __FUNCTION__, func_num_args());
$__cache = array();
return TRUE;
}
/* Installation du gestionnaire procédural de stockage défini par l'utilisateur */
if (!mysqlnd_qc_set_user_handlers("get_hash", "find_query_in_cache",
"return_to_cache", "add_query_to_cache_if_not_exists",
"query_is_select", "update_query_run_time_stats",
"get_stats", "clear_cache")) {
printf("Echec lors de l'installation du gestionnaire de stockage défini par l'utilisateur\n");
}
/* Connexion, création et peuplement de la table test */
$mysqli = new mysqli("host", "user", "password", "schema", "port", "socket");
$mysqli->query("DROP TABLE IF EXISTS test");
$mysqli->query("CREATE TABLE test(id INT)");
$mysqli->query("INSERT INTO test(id) VALUES (1), (2)");
printf("\nMise en cache/Absence du cache\n");
$res = $mysqli->query("SELECT id FROM test WHERE id = 1");
var_dump($res->fetch_assoc());
$res->free();
/* Suppression de l'enregistrement pour vérifier que nous récupérons bien nos
données depuis le cache */
$mysqli->query("DELETE FROM test WHERE id = 1");
printf("\nRécupération depuis le cache\n");
$res = $mysqli->query("SELECT id FROM test WHERE id = 1");
var_dump($res->fetch_assoc());
$res->free();
printf("\nAffichage des statistiques relatives au cache\n");
var_dump(mysqlnd_qc_get_cache_info());
printf("\nRé-initialisation du cache, mise en cache/absence du cache");
var_dump(mysqlnd_qc_clear_cache());
$res = $mysqli->query("SELECT id FROM test WHERE id = 1");
var_dump($res->fetch_assoc());
$res->free();
?>`

Les exemples ci-dessus vont afficher :

            query_is_select('DROP TABLE IF EXISTS test'): FALSE
            query_is_select('CREATE TABLE test(id INT)'): FALSE
            query_is_select('INSERT INTO test(id) VALUES (1), (2)'): FALSE

    Mise en cache/Absence du cache
            query_is_select('SELECT id FROM test WHERE id = 1'): 5
            get_hash(5)
            find_query_in_cache(1)
            add_query_to_cache_if_not_exists(6)
    array(1) {
      ["id"]=>
      string(1) "1"
    }
            query_is_select('DELETE FROM test WHERE id = 1'): FALSE

    Récupération depuis le cache
            query_is_select('SELECT id FROM test WHERE id = 1'): 5
            get_hash(5)
            find_query_in_cache(1)
            return_to_cache(1)
            update_query_run_time_stats(3)
    array(1) {
      ["id"]=>
      string(1) "1"
    }

    Affichage des statistiques relatives au cache
            get_stats(0)
    array(4) {
      ["num_entries"]=>
      int(1)
      ["handler"]=>
      string(4) "user"
      ["handler_version"]=>
      string(5) "1.0.0"
      ["data"]=>
      array(1) {
        ["18683c177dc89bb352b29965d112fdaa"]=>
        array(4) {
          ["hits"]=>
          int(1)
          ["bytes"]=>
          int(71)
          ["uncached_run_time"]=>
          int(398)
          ["cached_run_time"]=>
          int(4)
        }
      }
    }

    Ré-initialisation du cache, mise en cache/absence du cache    clear_cache(0)
    bool(true)
            query_is_select('SELECT id FROM test WHERE id = 1'): 5
            get_hash(5)
            find_query_in_cache(1)
            add_query_to_cache_if_not_exists(6)
    NULL