Système d’indexation

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.