Il y a beaucoup de choses à considérer, mais en général, je baserais la cartographie relationnelle dans votre cas sur la Row Data Gateway modèle (RDG). Si vous n'avez pas trop de types d'objets différents, cette approche de l'architecture devrait être suffisamment évolutive. RDG devrait faciliter votre implémentation de la mise en cache si vous limitez la comptabilité du cache à la classe Finder.
Si vous avez le temps et la volonté, consultez les Patterns of Enterprise Application Architecture de Martin Fowler . C'est un puits de bonnes informations.
Passons maintenant aux détails...
- identifier les données par une sorte d'identifiant
En règle générale, vous utiliserez une colonne entière auto-incrémentée dans la base de données pour cela. Vous pouvez utiliser unordered_map pour extraire rapidement ces objets du cache. Puisque vous avez tous les objets dans votre cache, dans un souci d'optimisation, vous pouvez également implémenter certains des find*
fonctions pour rechercher le cache en premier. Vous pouvez utiliser unordered_map/unordered_multimap pour "indexer" certaines des données, si votre temps de recherche est très limité, ou simplement vous en tenir au bon vieux map/multimap. Cependant, cela double le travail, et vous l'avez déjà gratuitement dans la base de données pour ce genre de requêtes.
- modifier les données/objets mis en cache
Les données modifiées ne doivent pas être visibles par le reste du système tant que vous ne les avez pas réellement écrites dans la base de données. Une fois que vous lancez la mise à jour, et si tout se passe comme prévu, vous pouvez soit remplacer l'objet en cache par celui que vous avez utilisé pour la mise à jour, soit simplement supprimer l'objet en cache et laisser les autres lecteurs le récupérer dans la base de données (ce qui entraînera en mettant à nouveau l'objet en cache). Vous pouvez implémenter cela en clonant l'objet Gateway d'origine, mais l'essentiel est que vous devriez avoir une stratégie de verrouillage implémentée.
- supprimer les anciennes données/objets et ajouter de nouvelles données/objets
Ici, vous supprimez simplement l'objet du cache et essayez de le supprimer de la base de données. Si la suppression échoue dans la base de données, d'autres lecteurs la mettront en cache. Assurez-vous simplement qu'aucun client ne peut accéder au même enregistrement pendant que vous êtes en train de supprimer. Lors de l'ajout de nouveaux enregistrements, vous instanciez simplement l'objet Gateway, le transmettez à l'objet de niveau domaine et, lorsque vous avez terminé les modifications, appelez insert sur l'objet Gateway. Vous pouvez soit mettre le nouvel objet Gateway dans le cache, soit simplement laisser le premier lecteur le mettre dans le cache.
- classer les données selon une sorte de priorité (dernière utilisation)
- Quel serait le meilleur moyen de mettre en cache les données/objets en fonction des informations fournies ET POURQUOI ?
Il s'agit de sélectionner le meilleur algorithme de mise en cache. Ce n'est pas une question facile à répondre, mais LRU devrait très bien fonctionner. Sans métriques réelles, il n'y a pas de bonne réponse, mais LRU est simple à mettre en œuvre et si cela ne répond pas à vos besoins, faites simplement les métriques et décidez d'un nouvel algorithme. Assurez-vous que vous pouvez le faire de manière transparente en ayant une bonne interface avec le cache. Une autre chose à garder à l'esprit est que vos objets au niveau du domaine ne doivent jamais dépendre des limites de votre cache. Si vous avez besoin de 100 000 objets, mais que vous n'avez que 50 000 cache , vous avez toujours tous les 100 000 objets en mémoire, mais 50 000 d'entre eux sont dans le cache. En d'autres termes, vos objets ne doivent pas dépendre de l'état de votre cache et ne doivent pas non plus se soucier de savoir si vous avez du cache.
Ensuite, si vous êtes toujours en train de découvrir l'idée de RDG, vous mettez simplement en cache l'objet Gateway dans votre cache. Vous pouvez conserver des instances des objets Gateway dans votre cache au moyen de shared_ptr, mais vous devez également envisager votre stratégie de verrouillage (optimiste vs pessimiste), si vous souhaitez éviter les écritures sales. De plus, toutes vos passerelles (une pour chaque table) peuvent hériter de la même interface, vous pouvez donc généraliser vos stratégies de sauvegarde/chargement, et aussi, vous pourrez utiliser un seul pool tout en gardant les choses simples. (Découvrez boost::pool. Peut-être que cela peut vous aider avec l'implémentation du cache.)
Un dernier point :
Le gateau est un mensonge! :D Peu importe ce que vous décidez de faire, assurez-vous qu'il est basé sur une quantité décente de mesures de performance. Si vous améliorez les performances de 20% et que vous avez passé 2 mois à le faire, il vaut peut-être la peine de penser à ajouter quelques Go de RAM supplémentaires à votre matériel. Faites une preuve de concept facilement vérifiable, qui vous donnera suffisamment d'informations pour savoir si la mise en œuvre de votre cache est payante, et si ce n'est pas le cas, essayez certaines des solutions testées et fiables sur étagère (memcached ou autre, comme @Layne l'a déjà commenté).