210 votes

Pourquoi le pilote Java de MongoDB utilise-t-il un générateur de nombres aléatoires dans une condition ?

J'ai vu le code suivant dans cet engagement para Le pilote de connexion Java de MongoDB et il semble d'abord que ce soit une sorte de blague. Que fait le code suivant ?

if (!((_ok) ? true : (Math.random() > 0.1))) {
    return res;
}

(EDIT : le code a été mis à jour depuis en postant cette question)

279voto

Marko Topolnik Points 77257

Après avoir examiné l'historique de cette ligne, ma principale conclusion est qu'il y a eu une programmation incompétente à l'œuvre.

  1. Cette ligne est gratuitement alambiquée. La forme générale

    a? true : b

    pour boolean a, b est équivalent à la simple

    a || b
  2. La négation ambiante et les parenthèses excessives compliquent encore les choses. En gardant à l'esprit Les lois de Morgan il est trivial de constater que ce morceau de code revient à

    if (!_ok && Math.random() <= 0.1)
      return res;
  3. L'engagement que a introduit à l'origine cette logique avait

    if (_ok == true) {
      _logger.log( Level.WARNING , "Server seen down: " + _addr, e );
    } else if (Math.random() < 0.1) {
      _logger.log( Level.WARNING , "Server seen down: " + _addr );
    }

    -un autre exemple de codage incompétent, mais remarquez le logique inversée : ici l'événement est enregistré si soit _ok ou dans 10% des autres cas, alors que le code de 2. renvoie à 10% des fois et les journaux 90% des fois. Donc le dernier commit a ruiné non seulement la clarté, mais la correction elle-même.

    Je pense que dans le code que vous avez posté, nous pouvons voir comment l'auteur avait l'intention de transformer l'original. if-then d'une manière ou d'une autre, littéralement dans sa négation requise pour les premiers return condition. Mais il s'est trompé et a inséré une "double négation" efficace en inversant le signe de l'inégalité.

  4. En dehors des questions de style de codage, la journalisation stochastique est une pratique douteuse en soi, en particulier parce que l'entrée du journal ne documente pas son propre comportement particulier. L'intention est, évidemment, de réduire les répétitions du même fait : que le serveur est actuellement hors service. La solution appropriée est d'enregistrer uniquement cambia de l'état du serveur, et non de chacune de ses observations, sans parler d'une sélection aléatoire de 10 % de ces observations. Oui, cela demande juste un peu plus d'effort, alors voyons voir.

Je ne peux qu'espérer que toutes ces preuves d'incompétence, accumulées en inspectant seulement trois lignes de code ne parle pas en bien du projet dans son ensemble, et que cette partie du travail sera nettoyée dès que possible.

17voto

msangel Points 1716

https://github.com/mongodb/mongo-java-driver/commit/d51b3648a8e1bf1a7b7886b7ceb343064c9e2225#commitcomment-3315694

il y a 11 heures par gareth-rees :

L'idée est probablement de n'enregistrer qu'environ 1/10 des pannes de serveur (et donc d'éviter de spammer massivement le journal), sans encourir le coût de la maintenance d'un compteur ou d'une minuterie. (Mais la maintenance d'une minuterie serait sûrement abordable).

7voto

tpdi Points 18427

Ajouter un membre de classe initialisé à la valeur négative 1 :

  private int logit = -1;

Dans le bloc try, faites le test :

 if( !ok && (logit = (logit + 1 ) % 10)  == 0 ) { //log error

Cela enregistre toujours la première erreur, puis toutes les dix erreurs suivantes. Les opérateurs logiques "court-circuitent", donc logit n'est incrémenté que lors d'une erreur réelle.

Si vous voulez le premier et le dixième de tous Les erreurs, quelle que soit la connexion, rendent la classe logit statique au lieu d'être un membre.

Comme cela a été noté, cela devrait être sans risque pour les fils :

private synchronized int getLogit() {
   return (logit = (logit + 1 ) % 10);
}

Dans le bloc try, faites le test :

 if( !ok && getLogit() == 0 ) { //log error

Note : Je ne pense pas que jeter 90% des erreurs soit une bonne idée.

1voto

Jens Timmerman Points 1448

J'ai déjà vu ce genre de choses.

Il y avait un morceau de code qui pouvait répondre à certaines "questions" provenant d'un autre morceau de code "boîte noire". Dans le cas où il ne pouvait pas y répondre, il les transmettait à un autre morceau de code "boîte noire" qui était très lent.

Parfois, de nouvelles "questions" inédites apparaissaient, et elles apparaissaient par lots, par exemple 100 d'affilée.

Le programmeur était satisfait de la façon dont le programme fonctionnait, mais il voulait un moyen d'améliorer le logiciel à l'avenir, si de nouvelles questions étaient découvertes.

La solution consistait donc à enregistrer les questions inconnues, mais il s'est avéré qu'il y en avait des milliers de différentes. Les journaux sont devenus trop gros, et il n'y avait aucun avantage à les accélérer, puisqu'ils n'avaient pas de réponses évidentes. Mais de temps en temps, il y avait un lot de questions auxquelles on pouvait répondre.

Comme les journaux devenaient trop volumineux et que la journalisation empêchait d'enregistrer les choses vraiment importantes, il a trouvé cette solution :

Ne consigner qu'un pourcentage aléatoire de 5 %, ce qui permet de nettoyer les journaux, tout en montrant à long terme quelles questions/réponses pourraient être ajoutées.

Ainsi, si un événement inconnu se produisait, dans un nombre aléatoire de ces cas, il serait enregistré.

Je pense que c'est similaire à ce que vous voyez ici.

Je n'aimais pas cette façon de travailler, alors j'ai supprimé ce bout de code, et j'ai juste enregistré ces messages dans un fichier différent Ils étaient donc tous présents, mais n'alourdissaient pas le fichier journal général.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X