Bonne structure de données de snapshottable pour un index en mémoire

12

Je conçois une base de données d'objets en mémoire pour un cas d'utilisation très spécifique. Il s'agit d'un rédacteur unique, mais il doit prendre en charge des lectures simultanées efficaces. Les lectures doivent être isolées. Il n'y a pas de langage de requête, la base de données ne prend en charge que:

  • obtenir un objet / -s par attribut / ensemble d'attributs (il peut y avoir un support pour les expressions, par exemple x.count < 5)
  • obtenir l'attribut de l'objet

Une requête est un script impératif composé d'un nombre arbitraire des opérations ci-dessus. La taille des données sera << mémoire, donc tous les objets et indices sur la plupart des attributs devraient s'adapter confortablement sans permutation.

Ce dont j'ai besoin, c'est d'une structure de données pour l'index d'attribut de l'objet, qui peut être O (n) lors des écritures, ne prend pas en charge la concurrence d'accès en écriture, mais devrait idéalement prendre en charge les instantanés O (1) (peut-être copier lors de l'écriture) et O (logN). Idéalement, cela permettrait une concurrence élevée sur les lectures avec un partage structurel maximal entre les versions.

Je regardais les CTries , les BST simultanés et les arbres de jeu simultanés, mais je ne sais pas si je regarde vraiment dans la bonne direction ici. Les structures ci-dessus prêtent beaucoup d'attention à la complexité des inserts qui ne m'intéressent pas.

La question : existe-t-il une structure de données connue qui convient bien à mon cas d'utilisation, prêt à l'emploi?

EDIT : après réflexion, il semble qu'un arbre BST / Splay persistant fonctionnerait. Le rédacteur mettrait à jour la copie «principale» et les requêtes obtiendraient l'arborescence dès le début de l'exécution et la jetteraient une fois qu'elles seraient terminées. Cependant, je suis toujours intéressé s'il y a une meilleure solution.

dm3
la source
1
Avez-vous besoin d'instantanés en mémoire ou devez-vous les enregistrer sur disque / réseau? Une structure de données purement fonctionnelle vous donne automatiquement des instantanés en mémoire, donc si c'est ce dont vous avez besoin, c'est votre meilleur pari.
Gilles 'SO- arrête d'être méchant'
Tout est en mémoire. Je me demandais peut-être qu'il existe une version mutable efficace avec un instantané à temps constant (comme CTrie, uniquement sans écritures simultanées).
dm3
2
Votre problème peut être moins le choix de la structure des données, mais le type de contrôle de concurrence.
Raphael
Peut-être pourriez-vous nous en dire un peu plus à ce sujet?
dm3

Réponses:

5

Utilisez tout type de structure de données arborescente persistante / immuable (c'est-à-dire fonctionnelle). La clé est d'obtenir le bon verrouillage, comme l'a souligné @Raphael dans les commentaires.

La bonne chose à propos des structures de données arborescentes fonctionnelles / persistantes, c'est que vous obtenez des "instantanés" gratuitement. Supposons que vous utilisiez un treap (arbre de recherche binaire randomisé) pour votre structure de données. Voici un exemple de celui écrit en Go: https://github.com/steveyen/gtreap . L'auteur le décrit ainsi:

Par immuable, toutes les mises à jour / suppressions d'un treap retourneront un nouveau treap qui peut partager les nœuds internes avec le treap précédent. Tous les nœuds de cette implémentation sont en lecture seule après leur création. Cela permet aux lecteurs simultanés de fonctionner en toute sécurité avec des écrivains simultanés, car les modifications ne créent que de nouvelles structures de données et ne modifient jamais les structures de données existantes. Il s'agit d'une approche simple pour réaliser MVCC ou le contrôle d'accès simultané multi-version.

O(logn)

Vous utilisez un verrou pour protéger le pointeur vers la racine. Comme la structure des données est immuable, les lectures peuvent être effectuées simultanément et vous pouvez enregistrer des pointeurs sur d'anciens instantanés. Une lecture est:

lock
tmp = ptr_to_root
unlock
value = search(tmp, <value to search for>)
return value

Même si la recherche peut prendre un certain temps, vous ne maintenez le verrou que lors de la copie du pointeur, de sorte que les recherches peuvent avoir lieu simultanément.

Une écriture c'est:

lock
old_ptr_to_root = ptr_to_root
ptr_to_root = insert(old_ptr_to_root, <new key/value pair>)
unlock

Dans cette version, les écritures doivent maintenir le verrou pendant tout le processus de création de la nouvelle version de l'arborescence. Vous pouvez améliorer les performances de lecture (au prix de l'échec de la transaction d'écriture) en changeant l'écriture en quelque chose comme ceci:

top:
  lock
  old_ptr_to_root = ptr_to_root
  unlock
  new_ptr_to_root = insert(old_ptr_to_root, <new key/value pair>)
  lock
  if (ptr_to_root == old_ptr_to_root)   # make sure no other write happened in the interim
    ptr_to_root = new_ptr_to_root
    unlock
  else                                  # transaction fails, try again
    unlock
    goto top

Vous pourrez peut-être faire encore un peu mieux (le rendre "sans verrouillage") si votre langage de programmation a des variables atomiques avec une opération atomique de comparaison et d'échange. (Par exemple en utilisant des C ++ 11. atomic<T*>)

Logique errante
la source
Merci pour la réponse élaborée. Je le savais en quelque sorte, peut-être que je n'ai pas mis cela assez clairement dans la question elle-même. Cependant, la réponse est toujours excellente!
dm3
Votre version "améliorée" dépend du modèle de mémoire du système utilisé. Il peut bien avoir besoin de verables pour être déclarés volatils sur certains systèmes et avoir besoin d'une grande compétence pour obtenir le codage correct.
Ian Ringrose
1

Microsoft a publié des détails sur leur nouvelle base de données en mémoire, il a des index qui ne bloquent pas les lectures pendant les écritures.

Par exemple:

Justin Levandoski, David Lomet et Sudipta Sengupta, The Bw-Tree: A B-tree for New Hardware, in 2013 IEEE 29th International Conference on Data Engineering (ICDE), International Conference on Data Engineering, 8 avril 2013.

Voir http://research.microsoft.com/en-us/projects/main-memory_dbs/ pour une liste de leurs publications.

Ian Ringrose
la source