7
votes

Quelles sont les implications de ne pas fermer une poignée d'annuaire dans Perl?

J'ai récemment hérité du code que quelqu'un d'autre avait écrit.

J'ai découvert que partout dans le code qu'un répertoire a été ouvert à la lecture, il n'a jamais été fermé car le développeur original avait un problème de syntaxe - il utilisait la fonction pour essayer de fermer un répertoire manipuler au lieu de la fonction fermétrir .

Le code était quelque chose comme ceci: xxx

(qui est un autre point de bon point est fabriqué dans Perl Meilleures pratiques (pages 208.278) sur la vérification du retour de la fonction Fermer . Si le retour du Fermer a été vérifié dans ce cas, il serait échoué avec " Numéro de fichier incorrect ".)

J'ai depuis modifié cela vers fermétrir , mais cela m'a fait commencer à me demander: puisque la poignée de répertoire n'a jamais été fermée, quelles sont les implications négatives à Garder une poignée de répertoire ouverte pendant une longue durée?

Ce programme est plus grand (3 500 lignes de code), fonctionne pendant un moment (5-10 minutes) et plusieurs instances de ce programme sont en cours d'exécution. temps. Dans le cas de ce répertoire dans l'exemple ci-dessus, $ dir est la même valeur pour toutes les instances. Si 10 instances de ce programme fonctionnaient simultanément, elles ont tous organisé une poignée de répertoire ouverte contre le même répertoire pendant 5 minutes ou plus. Je suis sûr que Perl ferme la poignée du répertoire automatiquement lorsque le programme se termine, mais la meilleure pratique indique de le fermer dès que possible.

Il est plus évident pour moi où les poignées de fichier laissant des problèmes peuvent causer des problèmes ( surtout pour les poignées de fichier ouvertes à l'écriture), mais quelles mauvaises choses peuvent se produire en ne fermant pas la fermeture d'une poignée de répertoire?

La raison pour laquelle je demande est parce qu'il y a eu une circonstance étrange dans laquelle ce programme essayait de Créez un fichier (dans le répertoire défini par $ dir ci-dessus). Le nom de fichier avait le PID intégré, il est donc une plus petite chance que le fichier puisse déjà être là, mais Perl n'a pas pu ouvrir le dossier pour écrire, car il l'a dit qu'il existait déjà. Lorsque nous avons examiné dans le répertoire, ce fichier n'existait pas. Je me demande si toutes les poignées Open Directory sur ce répertoire pourraient causer un tel problème?

Je ne sais pas si le système d'exploitation fait une différence, mais ce programme est en cours d'exécution sur AIX.

Merci d'avance et heureux vendredi!


0 commentaires

3 Réponses :


11
votes

Vous avez perdu un descripteur de répertoire - qui compte probablement en tant que descripteur de fichier. Cela vous ferait finalement vous faire mal si votre programme a ouvert suffisamment de répertoires pour fonctionner de descripteurs de fichiers. Sinon, c'est assez inoffensif, bien que moins qu'idéal. Il rend le système (et Perl) conserver les ressources autour desquels il pourrait autrement être capable de libérer.

Si la poignée du répertoire était une variable locale, pas un nom de style directeur uni, vous pourriez avoir un nettoyage de Perl derrière vous. Voir Opendir qui dit:

ouvre un répertoire nommé Expr pour le traitement par READDIR, TellDir, ReceisterDir, RewindDir et Fixer. Retourne vrai s'il réussisse. Dirhandle peut être une expression dont la valeur peut être utilisée comme un dirhandle indirect, généralement le nom du vrai dirhandle. Si Dirhandle est une variable scalaire non définie (ou élément de tableau ou de hachage), la variable est attribuée à une référence à un nouveau dirhandle anonyme. Les dirhandles ont leur propre espace de noms séparé de FileHhandles.


2 commentaires

Même aujourd'hui, certains OSS sont plutôt soudrets avec les descripteurs de fichiers (je regarde vous , Solaris et votre paramètre par défaut de 64-256).


@Mobrule - Je suis désolé, je ne peux pas publier votre commentaire, car il n'y a pas de descripteurs de fichier disponibles - sincèrement, Stackoverflow Solaris Solaris ....



8
votes

Il n'y aura pas de conséquences drastiques. Il y aura une très légère augmentation de l'utilisation de la mémoire, du noyau lui-même, qui ne peut pas libérer l'itérateur qu'il utilise à l'intérieur de la liste des entrées de répertoire, et probablement aussi du côté Perl.

ADITtionnel, tant que Comme tout descripteur de répertoire est toujours ouvert, les données ne peuvent pas être supprimées du système de fichiers. Si un autre processus externe supprimerait le répertoire que vous avez la poignée pour, il cesserait d'apparaître dans les futures listes de répertoires, mais les données devraient toujours être conservées sur le disque et seraient toujours accessibles par le processus avec la poignée ouverte. Cela pourrait entraîner des nombres impairs de l'utilisation des disques, par exemple. P>

Notez également que vous n'avez pas nécessairement de fermer toutes vos poignées manuellement. Lorsque vous utilisez des titres de fichiers lexicaux, la fermeture se produit automatiquement dès que la dernière référence à la poignée disparaît: P>

 { # new scope
     opendir(my $handle, ...) or ...;
     ...
 } # implicit closedir happens here


0 commentaires

7
votes

Il s'agit d'une leçon pour toujours utiliser des poignées lexicales (et de répertoires) - les poignées lexicales sont automatiquement fermées lorsqu'elles sortent de la portée.

Donc, vous ne seriez que gaspiller descripteurs (comme le décrit Jonathan) si 1. Vous avez utilisé la poignée Glob de style ancienne ou 2. Tout le code est dans un scope plat sans sous-routine ou autre scopage. Utilisez de bonnes pratiques de programmation et des erreurs par inadvertance seront moins :)


2 commentaires

Cet opendir était principal, donc il était globalement scopé ... Vous êtes absolument juste, cependant - de bonnes pratiques de programmation réduiront définitivement des erreurs par inadvertance!


Selon votre code, vous avez utilisé une poignée de mots nu. Celles-ci sont toujours globalement scopées à moins que vous les localisez explicitement.