Master 2, Bases de données avancées, année 2023

Suite du TP sur Redis

L’objectif de l’examen est de vérifier votre compréhension des concepts suivant:

  1. Key Value Store
  2. Écrire des requetes SQL standard
  3. Le Sharding

Les questions sont essentiellement indépendantes de celles du TP2, nous allons créer un key-value store avec PostgreSQL pour remplacer redis.

Rendu du TP2

Préparer ce que vous avez fait dans le TP2 pour être rendu.

Je veux avoir un unique archive (format zip ou tar.gz) avec:

Vous pouvez prendre un peu de temps pour remettre en forme votre TP mais attention, c’est du temps que vous ne mettrez pas sur le reste de l’examen.

Dans le repertoire Exam, vous pouvez copier vos fichiers de TP2 et repartir de cette base pour continuer.

La note prendra en compte la qualité des rendus dans Exam ET la qualité de TP2.

Le rendu est à faire par mail

Dans le README:

ssh ubuntu@ip-address "curl -s https://paperman.name/data/scripts/prepare.sh | sh"
ssh: Could not resolve hostname ip-address: Name or service not known

De Redis à PostgreSQL

Nous allons remplacer la base de donnée Redis par une base de données PostgreSQL.

Pour ce faire, vous allez réaliser les taches suivantes:

  1. Créer une base de données dans votre instance principale de PostgreSQL
  2. Créer un schéma SQL pour modéliser une instance Redis.

Vous pouvez tout mettre dans une seule table, mais vous devez modéliser le fait qu’on peut héberger plusieurs BDD redis sur une instance Redis numérotées de 0 a 16.

Les valeurs doivent être des blob binaires, vous pouvez utiliser pour ça le type PostgreSQL BYTEA, pour Byte Array.

import json
L = ["je suis", 1, "Liste"]
s = json.dumps(L)
print(s)
["je suis", 1, "Liste"]

Et

K = json.loads(s)
print(L == K)
True

De même pour les dictionnaires:

d = {"je":"suis", "un":"dict"}
s = json.dumps(d)
print(s)
{"je": "suis", "un": "dict"}

Et

K = json.loads(s)
print(d == K)
True
  1. Écrire dans votre middleware une classe KeyValueStore qui permet de récupérer, d’ajouter et de supprimer des clefs dans la base de donnée PostgreSQL.

Vous pouvez utiliser le template de code suivant en remplaçant ... par un code qui execute une requête à l’aide de l’objet cursor et qui retourne le résultat quand cela est nécessaire (principalement pour le getitem).

from collections.abc import MutableMapping
import psycopg

def wrap_connect(fct):
    def _f(self, *args):
        with psycopg.connect(**self.db_connect) as db:
            with db.cursor() as cursor:
                return fct(self, cursor, *args)
    return _f

class KeyValueStore(MutableMapping):
    def __init__(self, db_index, **kwargs):
        self.db_connect = kwargs
        self.db_index = db_index

    @wrap_connect
    def __delitem__(self, cursor, key):
        """ Doit supprimer la clef de self.db_index """
        ...

    @wrap_connect
    def __setitem__(self, cursor, key, value):
        """ Doit associer key a value dans self.db_index """
        ...
    @wrap_connect
    def __getitem__(self, cursor, key):
        """ Récupère la valeur de key dans self.db_index """
        ...
        x = cursor.fetchone()
        if x is None:
            raise KeyError()
        return x

    @wrap_connect
    def __iter__(self, cursor):
        """ Retourne la liste de toutes les clefs de self.db_index """
        ...

    @wrap_connect
    def __len__(self, cursors):
        """ Retourne le nombre de clefs dans self.db_index """
        ...

L’usage de cette classe devient alors:

db0 = KeyValueStore(0, port=5432, host="localhost") # retourne la db 0
db1 = KeyValueStore(1, port=5432, host="localhost") # retourne la db 1

Intégrer

Modifier votre middleware pour utiliser la classe KeyValueStore en place de Redis. Vérifier que cette dernière marche toujours.

Sharding

Créez une deuxième base de données PostgreSQL sur la même VM.

Vous pouvez utiliser la commande pg_createcluster 14 main2 par exemple, en tant qu’utilisateur postgres

Pour connaitre le port vous pouvez utiliser la commande pg_lsclusters

Nous allons implémenter un mécanisme de Sharding avec cette nouvelle base. Creez une classe KeyValueStoreSharding en éditant le template suivant:

class KeyValueStoreSharding(MutableMapping):
    def __init__(self, K1: KeyValueStore, K2: KeyValueStore):
        ...

    def __delitem__(self, key):
        ...

    def __setitem__(self, key, value):
        ...

    def __getitem__(self, key):
        ...

    def __iter__(self):
        ...

    def __len__(self):
        ...

Pour aller plus loin


Compiled the: mar. 19 mars 2024 16:13:09 CET