2009-09-03 9 views
2

J'ai cette commande dans un contrôleur Railset fichier temporaire Garbage Collection

open(source) { |s| content = s.read } 
    rss = RSS::Parser.parse(content, false) 

et entraîne dans des fichiers temporaires qui comblent l'espace disque (rare).

J'ai examiné le problème dans une certaine mesure, et il se trouve quelque part dans la pile cela se produit:

io = Tempfile.new('open-uri') 

, mais il semble que cette instance n'est jamais explicitement fichier temporaire fermé. Il a une

def _close # :nodoc: 

méthode qui pourrait se déclencher automatiquement lors de la récupération de place?

Toute aide pour savoir ce qui se passe ou comment nettoyer les fichiers temp serait utile.

Répondre

1

il semble que _close ferme le fichier, puis attend la récupération de place pour dissocier (supprimer) le fichier. Théoriquement, vous pouvez forcer la dissociation immédiatement en appelant la méthode close! de Tempfile au lieu de close, ou d'appeler le close(true) (qui appelle close! en interne).

modifier: Mais le problème est en plein uri, ce qui est hors de vos mains - et qui ne fait aucune promesse pour le nettoyage après lui-même: il suppose simplement que le garbage collector finalisera tous Tempfile s en temps utile .

Dans un tel cas, vous n'avez pas d'autre choix que d'appeler vous-même le collecteur de données à l'aide de ObjectSpace.garbage_collect (see here). Cela devrait entraîner la suppression de tous les fichiers temporaires.

+0

Qui appelle _Fermer? Sans patch de singe, je n'ai pas accès à ce fichier temporaire, je pense. –

+0

Je vois le problème maintenant. J'ai ajouté quelques informations à la réponse, j'espère que cela fonctionnera pour vous. – Guss

+0

Merci pour cela! Je ne peux pas imaginer qu'appeler explicitement le GC résoudra le problème. Dans mes tests, la seule façon d'obtenir un fichier temporaire pour ne pas être nettoyé est d'interrompre le programme. Donc, je ne peux pas comprendre ce qui pourrait arriver. –

1

Certainement pas un bug, mais une erreur de manipulation des E/S. Buffer.io est soit StringIO si le @size est inférieur à 10240 octets ou un fichier Temp si plus de cette quantité. La clause Ensure dans OpenURI.open_uri() appelle close(), mais comme il pourrait s'agir d'un objet StringIO, qui n'a pas de méthode close (!), Il ne peut simplement pas appeler close!().

Le correctif, je pense, serait l'un d'entre eux:

La clause d'assurer un contrôle de la classe et demande soit StringIO.close ou Tempfile.close! comme requis.

--ou--

La classe a besoin d'un tampon finaliseur qui gère le contrôle de la classe et appelle la méthode correcte. Certes, ni l'un ni l'autre ne le corrige si vous n'utilisez pas de bloc pour gérer les E/S, mais je suppose que dans ce cas, vous pouvez faire vos propres vérifications puisque open() renvoie l'objet IO, pas le Buffer objet. Le lib est un gros morceau de code malpropre, à mon humble avis, donc il pourrait utiliser un work-over pour le nettoyer. Je pense que je pourrais le faire, juste pour m'amuser. ^.^

+0

SynTruth, j'ai l'idée, mais dans un langage de dactylographie, vous n'avez pas vérifiez la classe. Vous vérifiez s'il répond à une méthode :). En tout cas, je suis si loin de ce problème maintenant que je ne saurais pas si vous l'avez réparé. Mais rapportez si vous le faites, juste pour la curiosité. –

4

Si vous voulez vraiment forcer open-uri ne pas utiliser un fichier temporaire, vous pouvez jouer avec la constante OpenURI::Buffer::StringMax:

> require 'open-uri' 
=> true 
> OpenURI::Buffer::StringMax 
=> 10240 
> open("http://www.yahoo.com") 
=> #<File:/tmp/open-uri20110111-16395-8vco29-0> 
> OpenURI::Buffer::StringMax = 1_000_000_000_000 
(irb):10: warning: already initialized constant StringMax 
=> 1000000000000 
> open("http://www.yahoo.com") 
=> #<StringIO:0x6f5b1c> 

C'est à cause de cet extrait de open-uri.rb:

class Buffer 
    [...] 
    StringMax = 10240 
    def <<(str) 
    [...] 
    if [...] StringMax < @size 
     require 'tempfile' 
Questions connexes