Entries for tag mongodb

Wed Sep 15 2010

C++, MongoDB, Programming

asio, boost, bson, c++, mongodb, mongoxx, proto

9 comments

mongoxx, driver C++ alternatif pour MongoDB

J'utilise MongoDB pour une poignée de projets mais je n'ai jamais eu besoin des différents drivers python, php ou encore javascript. Aucun, sauf le driver C++. Bon, OK, si on considère que le shell mongo est un driver javascript, alors oui, je l'utilise beaucoup[1].

Le driver C++ est intimement lié au projet MongoDB dans la mesure où il est maintenu par les core developers -une partie du staff de 10gen- et qu'il partage la plupart de ses sources avec celles du server.

Il y a des avantages à ce qu'un tel driver soit à ce point corrélé au server. Premièrement, il fait partie du cercle fermé des drivers officiels, ceux développés par 10gen. Deuxièmement, des améliorations au niveau du server peuvent être répercutées sur le driver puisque les sources sont communes (par exemple les mécanismes de réplication). Enfin, comme la plupart des tests unitaires et fonctionnels du projet s'appuient sur ce driver, nul besoins de préciser que ses bugs sont corrigés en priorité.

Maintenant, les désavantages, car il y en a.

Compiler le driver, c'est à dire obtenir libmongoclient et une série de fichiers headers n'est pas si simple que ça. Le build system de MongoDB est basé sur SCons, un software construction tool écrit en python. SCons est un très bon outil. Un projet est construit (compilé, installé etc) à l'aide d'instructions python présentes dans un fichier SConstruct ainsi que, optionnellement, autant de fichiers SConscript qu'il y a de sous-répertoires et sous-projets.

MongoDB est une collection de projets. Le server principal mongod, mais aussi des tools tels que mongosniff, mongodump, le shell mongo, des exécutables pour les tests ou le driver C++ qui est, comme nous l'avons vu, une librairie qui se compile et est pleinement intégrée au source tree principal.

MongoDB n'a recours qu'à un seul et unique fichier SConstruct pour compiler et installer tous les sous-projets pour toutes les plateformes (diverses distribs Linux, Solaris, Windows, 32bit, 64bits etc). Le fichier a grossi exponentiellement. Celui-ci est régulièrement tweaké au gré des besoins imposés par un rythme de développement soutenu.

Cela n'est pas gênant dans la mesure où la méthode conseillée pour installer MongoDB est de télécharger des packages prêts à l'emploi pour une plateforme donnée. Nul besoin de lancer ni même installer SCons. Comme la plupart des applications utilisant MongoDB sont écrites en ruby, python ou php[2] et que leurs drivers respectifs sont développés sur des canaux séparés, la majorité des utilisateurs n'a que faire des subtilités du build system.

Seul les core devs, les buildbots et les utilisateurs du driver C++ (et bien sûr les hackers en tout genre;) sont amenés à s'adapter. C'est mon cas. Depuis le début, je maintiens un fork qui me permet de m'accomoder en douceur, si je puis dire.

Pendant un temps, j'ai soumis quelques patches en fonctions des problèmes que je rencontrais. Par exemple le fait d'utiliser spidermonkey en provenance du dépot mercurial de mozilla-central plutôt que des tarballs individuels ou des packages (j'ai depuis switché pour V8). Ou encore le fait d'utiliser diverses versions de GCC avec différents flags.

Le driver C++ a toujours eu un statut un peu bâtard, principalement parce que personne ne l'utilise à part le projet MongoDB, ou presque. Récemment, les choses se sont dégradées et à moins de bidouiller le build system, il n'est plus possible d'effectuer une installation conforme dans un répertoire cible contenant les includes et lib nécessaires, et donc ne pas pénaliser les projets qui dépendent d'une telle installation.

Grâce à mon fork, ça va, je gère.. pour l'instant. Ce n'est pas le cas de tout le monde. Les gars de 10gen ont prévu de normaliser la situation. Comme ils savent un peu (légèrement;) mieux que moi ce qu'il faut faire pour opérer un découplage propre sans briser tout le reste, je prends mon mal en patience.

...jusqu'à il y a quelques jours. Après tout, quel intérêt ai-je à dépendre de ce driver, qui même correctement compilé et installé, n'est pas dénué de défauts comme nous allons le voir.

Quand j'ai commencé à écrire mes premiers codes utilisant ce driver, ce qui m'a le plus étonné et frustré était à quel point les développeurs ont été peu précautionneux au regard des pratiques élémentaires d'importation des namespaces C++.

En gros, le moindre include de header mongo avait pour conséquence d'importer tous les symbols de la librairie standard, mais aussi quelques namespaces de la librairie Boost, dans le namespace global. C'est simple, Il était impossible d'utiliser le driver C++ pour un projet autre que MongoDB lui-même. Heureusement, un fix d'antologie -par votre serviteur- a permis de limiter les dégâts à moindre frais ;) Maintenant, c'est le namespace mongo qui est pollué. Un soin curatif complet demanderait une qualification complète de tous les noms dans tous les fichiers headers et des importations sur demande dans les fichiers sources. Une tâche longue et fastidieuse que personne n'a eu le courage d'entreprendre.

mongoxx

Du coup j'ai entrepris d'écrire mon propre driver C++, mongoxx, entièrement découplé des sources de MongoDB. L'idée, c'est que ce soit découplé, d'accord, mais surtout explorer certaines librairies Boost que je n'ai jamais encore utilisé. Je pense à Proto ou Move dont la review est pending. Pour la partie communication, Asio bien entendu.

Quid de BSON, le format "JSON binaire" omniprésent dans MongoDB? Je n'ai pas trouvé de container suffisamment souple avec lequel travailler pour implémenter les specs BSON. Un std::vector<char> ne fait pas complètement l'affaire, pas plus qu'un boost::array.

Du coup je me suis monté un container binaire générique qui repose ultimement sur des malloc/realloc et que j'utilise pour implémenter BSON mais aussi pour construire les messages envoyés au server qui contiennent souvent des docs BSON en plus de headers/flags spécifiques.

Mes premiers essais avec Proto sont vraiment fantastiques ;) Cette librairie est une tuerie. Un petit teaser:

// 'doc_', 'genoid', 'undefined', 'now' sont des terminals proto.
// l'espace mémoire requis est calculé à la compilation
// si possible (pod types) 
 
doc d = doc_
    ("_id", genoid)
    ("machin", "ok")
    ("truc", undefined)
    ("embed", doc_
        ("val", 3.14)
        ("date", now))
;
 
d << "last" << 42; // grows as needed
 
// STL iterator ready
std::for_each(d.begin(), d.end(), [](elem const& e){
    pretty_print(e);
});

Le but c'est que l'interface du driver soit simple et à peu près conforme aux conventions de la librairie standard ainsi que Boost, ce que le driver C++ de MongoDB n'est pas du tout. Par exemple être compatible avec les itérateurs pour parcourir des documents BSON ou des results sets et donc pouvoir y appliquer les algorithms standards.

Actuellement j'ai un chantier de proofs of concept que je veux résorber et structurer, en commençant par y ajouter des tests unitaires avant d'aller plus loin. Je push ensuite tout ça sur github. Comme je souhaite me débarrasser complètement de libmongoclient, je ne vais pas vous cacher que j'ai encore pas mal de boulot ;)

[1] Une bonne partie de l'administration de ce site se fait à partir d'un shell mongo.

[2] MongoDB survey results publié le 18 Fev 2010.

Thu Dec 24 2009

Blog, Vrac

blog, c++, linode, linux, mongodb, nginx, v8

0 comment

Bilan du blog pour 2009

2009 s'achève. Encore une année passée à fond la caisse. Rien vu passé en fait. Fin d'année rime avec bilan et bêtisier (et prévisions astrologiques, mais on n'en a rien à foutre). Ok. RAS pour l'intro.

Au mois de février, ou un truc du genre, je m'étais juré d'ouvrir un blog. Je m'étais dit la même chose l'année précédente et l'année d'avant aussi. Bref, y a quelque chose qui a sérieusement merdé en 2009 pour que ce blog puisse enfin voir le jour.

Ce qui a déconné grave en 2009

Tout a commencé avec l'envie inexpliquée de me choper un VPS. Après investigations, mon choix s'est porté sur Linode. A postériori, ce choix n'était pas mauvais puisque leurs plateformes Xen déchirent leur race. Bon, j'aurais pu faire l'erreur de me trouver piéger quant aux choix de l'OS, du kernel et tout, mais non, il a fallu que Slackware soit dispo. Franchement là je commençais à me dire "putain avec ces conneries tu vas finir par l'ouvrir ton blog". Je vous raconte pas les boules.

En parallèle, la nécessité de plus en plus pressante de changer de laptop se faisait.. de plus en plus pressante. En gros, je lorgnais sur des ASUS de gamers, de quoi assouvir mes envies de meurtres et pouvoir y foutre sereinement une distrib linux en dual boot. Pourquoi ASUS, pourquoi un PC d'ailleurs ? C'est une excellente question, mais j'ai autre chose à foutre faire que d'y répondre (j'ai déjà mis foutre deux phrases plus haut). Non, vraiment, la seule chose dont j'étais sur, c'est que MOI vivant, JAMAIS je ne claquerais 1500 euros dans une arnaque de MacBook. Encore une heure avant de me rendre sur l'App Store un soir et y claquer frénétiquement juste à peine moins de 1500 euros tel un maniaco compulso-dépressif, j'aurais maintenu mes positions sous la tortures. Heureusement que je suis blindé de thunes.

Essayons de bien comprendre: à ce moment là de l'année, rien ne se passait comme prévu. Putain j'allais quand même pas finir par installer Wordpress ou Dotclear. Si près du but, sans la moindre embuche, c'est pas possible ou quoi. Y a pas moyen.

Une solution de secours: virer LAMP

Et remplacer cette stack par LEMC++. Une solution de secours à la RACHE, nous sommes d'accord. Au moins avec un peu de chance ça devrait pouvoir ruiner ce qu'il restait de 2009, d'autant plus que je m'étais dis "hum hum, tu vas te remettre à la guitare".

Pas le temps de placer 3 accords de 7ième mineur, que déjà mon VPS compile GCC trunk plus rapidement que le Mac. Et les gars de Linode ne bronchent pas. Il ne s'agit pourtant que d'un plan 360. Moi je vous dis, ça pue... d'autant plus que les concours de circonstances fortuites et malheureuses s'enchainent:

Consternant. Et ce n'est pas un ApacheBench qui viendra contrecarrer cet état de fait. Oui, c'est affligeant, mais cette daube encaisse plus de 5000 requêtes par seconde.

Server Software:        nginx/0.8.27
Server Hostname:        blog.runpac.com
Server Port:            80

Document Path:          /
Document Length:        21134 bytes

Concurrency Level:      10
Time taken for tests:   0.173 seconds
Complete requests:      1000
Failed requests:        0
Write errors:           0
Total transferred:      21271000 bytes
HTML transferred:       21134000 bytes
Requests per second:    5779.68 [#/sec] (mean)
Time per request:       1.730 [ms] (mean)
Time per request:       0.173 [ms] (mean, across all concurrent requests)
Transfer rate:          120058.15 [Kbytes/sec] received

Sur du 360...

$ free -m
             total       used       free     shared    buffers     cached
Mem:           348         77        271          0         17         42
-/+ buffers/cache:         17        330
Swap:          255          0        255

Mais qu'est-ce qui a bien pu déconner ??

Sauvé par les stats de visites

Manquerait plus que le site soit fréquenté! Après un mois et demi d'existence, seul une poignée d'inconscients (autres que les déferlantes de bots google et baidu) atterrissent ici. Franchement, au début j'ai eu peur. Déjà que je me fais chier à blogger en français EXPRES. Par chance vous n'êtes pas plus de 20 peulés chaque jour à perdre votre temps ici.

Faite gaffe quand même. 2009 n'est pas fini.