Afin d’améliorer les performances du moteur d’informations de Generic System, un système de cache automatique qui évite la répétition de requêtes coûteuses au back-office a été mis en place.
De nombreuses méthodes qui renvoient un Snapshot font par exemple appel à la méthode getDependencies(), suivie d’un ou plusieurs filtres (seulement les instances, une valeur ou des composants donnés, etc.). Pour éviter d’avoir à re-filtrer les Snapshot à plusieurs reprises, nous avons créé des arbres permettant de stocker les résultats des filtrages dans les classes AbstractTsDependencies et PseudoConcurrentCollection. L’arbre est constitué de nœuds contenant :
- l’index lui-même, sous forme d’implémentation de l’interface Index fournissant les méthodes add(), remove() et iterator() ;
- des enfants sous forme de HashMap ayant pour clés des IndexFilter et pour valeur le nœud contenant l’index filtré avec sa clef. Les entrées sont créées automatiquement lors du get() si elles n’existent pas. La méthode filter(List filters) va chercher le nœud de l’arbre correspondant aux filtres indiqués.
Utilisation des index
Afin d’utiliser ces index, plusieurs méthodes ont été ajoutées dans l’interface Snapshot :
- unfilteredStream()
- getFilter()
- getParent()
- filter(IndexFilter filter)
- filter(List filters)
La méthode
unfilteredStream() est appelée pour créer le stream du
Snapshot quand aucun filtre n’est appliqué. Elle doit être définie dans toutes les implémentations de
Snapshot. Les méthodes
getFilter() et
getParent() renvoient
null par défaut, mais
filter(IndexFilter filter) construit un
Snapshot enfant du
Snapshot courant ayant le filtre indiqué.
La méthode
stream() remonte les parents en accumulant les filtres et appelle
filter(List filters) sur la racine de l’arbre dans le cas où un ou plusieurs filtres étaient présents, et
unfilteredStream() dans le cas contraire.
Par défaut, la méthode
filter(List filters) retourne un
Snapshot dont la méthode
unfilteredStream() est redéfinie pour appliquer tous les filtres fournis. Les implémentations de
Snapshot utilisant des
AbstractTsDependencies ou des
PseudoConcurrentCollection redéfinissent
filter(List filters) afin d’aller chercher les données stockées dans les arbres d’index au lieu de refaire les calculs comme le fait l’implémentation par défaut.
Enfin, pour éviter que les HashMap utilisées pour stocker les index finissent par saturer la mémoire, on stocke des SoftReference aux valeurs au lieu de stocker directement les valeurs fournies. Les SoftReference sont enregistrées auprès d’une ReferenceQueue, ce qui permet de supprimer les entrées de la map lorsque la valeur a été garbagée.
La mise en place de ce système d’indexation a permis d’accélérer considérablement l’entrée en base de quantités relativement importantes de données. Il reste cependant des améliorations à faire, par exemple pour choisir l’ordre de filtrage le plus adapté ou éviter de refaire les calculs lorsque l’on utilise les mêmes filtres dans des ordres différents.