Futur De RamSQL

#ramsql #go

RamSQL est un moteur SQL léger, en RAM, qui a pour objet d’aider à

  • vérifier la validité des schémas SQL
  • vérifier facilement la validité des queries SQL

Ce projet a 8 ans maintenant. Désormais de nombreux “vrai” SQL engines propose un mode “in memory”

ou encore faire tourner un container dans la CI pour les tests.

Bref, la première question à se poser concernant le futur de RamSQL c’est de savoir s’il faut archiver le projet et pointer vers d’autres solution.

Archiver le projet ?

Je veux essayer de lister dans cette section des arguments en faveur de RamSQL, qui justifieraient de poursuivre le développement. Mais commençons par les arguments en faveur d’un archivage.

Grammaire SQL incomplète

La grammaire gérée par RamSQL n’est pas complète, et ne sera jamais aussi complète que celle de SQLite ou MySQL. Le travail à fournir est titanesque et je suis loin de gérer l’ensemble des corners cases.

Pas d’Index

Les index ne sont pas implémenté, ce qui empêchent tout tests de query lié à un index spécifique. Aujourd’hui le CREATE INDEX n’est même pas parsé, ce qui empêche même la validation de la plupart des fichiers de schémas SQL.

CREATE TABLE some_table (id BIGSERIAL AUTOINCREMENT, name TEXT, content TEXT);
CREATE INDEX some_table_index ON some_table (name, content);
$ ramsql < index.sql
ramsql> Query OK. 1 rows affected
ramsql> ERROR : cannot execute : Parsing failed, unknown token index
ramsql> exit

Pas de Foreign Key

Encore une fois, le principe même de RamSQL étant de tester la validité des queries avec des tests unitaires, si les contraintes de foreign key ne sont pas respecté, l’intérêt est limité.

Pas de Returing

Composant assez classique d’une query d’insert, le RETURING ne fonctionne pas vraiment, l’implémentation est bancale

Plusieurs deadlocks

Le code comporte pas mal de deadlock qui sont difficilement resolvable vu la qualité du code.

Pas de release sur Github, ni de tag v1.

Les utilisateurs n’ont aucune idée de ce à quoi s’attendre avec RamSQL en arrivant sur la page du projet. Le code n’est pas tagué, il n’y a pas de release note, et aucune matrice de feature set n’est présente dans le README. Personnellement, je n’aurais pas confiance.

Continuer le projet ?

Oui mais…RamSQL a peut-être encore une place dans l’écosystème des imdb, spécifiquement dans l’écosystème du testing.

Rapidité d’exécution

Écrire un test avec RamSQL c’est avoir la rapidité de son coté. Les gens développent en Go en partie parce que la compilation est très rapide, on veut aussi des tests rapide. Impossible de faire du TDD s’il faut plus de 30s pour executer la test suite entière.

Et là ben…RamSQL est devant. C’est un package Go, le code tourne dans le même process que les tests. Pas d’histoire de docker, pas de setup externe. Le setup/teardown d’un test utilisant RamSQL est de 5ms.

$ time go test -count=1 -v ./... | grep PASS | wc -l
121

real    0m0.851s
user    0m1.125s
sys     0m1.547s

Portabilité

Encore une fois, c’est une lib Go. RamSQL a le même niveau de compatibilité que Go: pas de bindings C/pas d’installation de docker.

Dead simple

Less is more, toussa.

Cependant, la facilité d’utilisation de RamSQL est toujours très agréable, à chaque fois que j’en ai eu besoin. Il suffit d’importer le driver et c’est parti.


import (
    "testing"

    _ "github.com/proullon/ramsql"
)

func TestCRUD(t *testing.T) {
    db, err := sql.Open("ramsql", "TestCRUD")
    db.Exec(`CREATE TABLE my_stuff (...)`)
    id, err = InsertStuff(db, stuff)
    stuff, err := GetStuff(db, id)
    err = DeleteStuff(db, if)
}

Done.

C’est utilisé

Malgré l’ensemble des limitations et des bugs, RamSQL est utilisé. J’ai envie de faire en sorte que ces gens aient au moins une version clean.

D’après Github, le traffic journalier sur RamSQL est d’une centaine de visite unique et le double pour les clones.

Ce qui nous amène à…

RamSQL v1.0

Objectif v1.0 pour RamSQL. Je ne sais pas si j’aurais envie de continuer le développement ensuite, mais au moins le projet sera propre, et la documentation également.

Je veux que d’un coup d’oeil au README, on puisse savoir si RamSQL convient.

Je veux que le projet soit bugfree dans le scope défini.

Je veux que les avantages et inconvénient soient clairement documentés.

Features SQL

Features dédiées au testing

Query history

RamSQL devrait sauvegardé les queries exécutées pour permettre un debug plus facile, j’ai utilisé RamSQL récemment pour un test technique et je me suis surpris à vouloir cette feature.

CLI breakpoint

Je veux qu’il soit possible au milieu d’un test d’intégration de stopper l’application et d’ouvrir la CLI de RamSQL. Cette feature permettrait de servir de breakpoint pour inspecter le contenu de la db avec un lock complet, ce qui mettrait de facto en pause le programme à debug.

Encore une fois, j’aurais aimé avoir cette feature au moment de debug une valeur étrange inséré au fin fond d’une goroutine lors d’un test technique.

Better CLI

Les deux derniers points implique également d’améliorer la CLI pour intégrer l’historique, up, down, etc.

Autogeneration

Taille maximale d’une table ou de la database

Il y a une issue ouverte pour cette feature request, je n’y avais pas pensé mais ça peut être intéressant pour faire un peu de chaos engineering.

Features dédiées au LFRU caching

J’ai eu plusieurs fois le cas d’usage d’un LFRU en cache directement dans l’application, que ce soit une grosse table avec une petite partie chaude, soit simplement une petite table. J’avais une grosse contrainte réseau par contre, donc cacher facilement dans l’application directement au lieu de tabasser un redis a fait gagner des perfs énormes, pour quelques Gb de RAM.

Il “suffit” que quelques éléments soient présents.

Peut-être que RamSQL peut fournir le nécessaire:

  • Indexing (facile si c’est fait de toute façon)
  • RAM limit (facile si c’est fait de toute façon)
  • Algorithme LFRU activable sur une table

Reste le cache invalidation à plug quelque part.

Architecture technique

Réecriture

Le projet entier a besoin d’être réécrit. J’étais parti à l’époque avec l’idée de communiquer localement via channel entre le driver et l’engine, mais avec l’objectif de feature set actuel ce n’est pas nécessaire.

L’engine doit être réécrit avec transactions from scratch, pour permettre l’implémentation des transactions et auto-commit.

Les tests doivent être triés et regroupés, pour faciliter le travail des contributeurs.

Le binaire CLI doit être bougé dans cmd/ramsql, pour permettre d’importer github.com/proullon/ramsql qui contiendrait les features de tests et debug.

Documentation

Le projet doit être documenté avec:

  • Matrice croisée de features avec les catégories planned parsed implemented
  • Objectif final de cas d’usage
  • Code d’exemple pour du test et du LFRU caching

Roadmap

  • Transaction object
  • Relation rewrite
    • transaction safe
    • size counting
    • map[int]int indexes
  • Engine rewrite
    • query history
    • transaction safe
  • ramsql.CLI()
  • ramsql.Generate()
  • ramsql.History()
  • Parser generation with BnF grammar
  • Size limits
  • Indexes
  • LFRU