Merge lp:~cjwatson/txpkgupload/fix-leak into lp:~lazr-developers/txpkgupload/trunk

Proposed by Colin Watson
Status: Merged
Approved by: Colin Watson
Approved revision: 21
Merged at revision: 21
Proposed branch: lp:~cjwatson/txpkgupload/fix-leak
Merge into: lp:~lazr-developers/txpkgupload/trunk
Diff against target: 94 lines (+22/-16)
2 files modified
src/txpkgupload/plugin.py (+5/-1)
src/txpkgupload/twistedsftp.py (+17/-15)
To merge this branch: bzr merge lp:~cjwatson/txpkgupload/fix-leak
Reviewer Review Type Date Requested Status
William Grant code Approve
Review via email: mp+247276@code.launchpad.net

Commit message

Fix memory leak when closing SFTP connections.

Description of the change

Yesterday evening there was an outage due to txpkgupload having leaked to the point where it was using rather more than 4GB of memory. I looked into this a bit today and found that I could make it leak just by repeatedly initiating SFTP connections. This is happening because it registers a global handler for SFTPClosed on every connection and never unregisters it. Rather than going through the component registry for this, it seems easier to just subclass FileTransferServer, and with this change memory use remains stable when hammering the server with consecutive no-op SFTP connections in a loop.

To post a comment you must log in.
Revision history for this message
William Grant (wgrant) :
review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'src/txpkgupload/plugin.py'
--- src/txpkgupload/plugin.py 2015-01-21 12:50:43 +0000
+++ src/txpkgupload/plugin.py 2015-01-22 11:33:13 +0000
@@ -43,7 +43,10 @@
43 ReadyService,43 ReadyService,
44 )44 )
45from txpkgupload.twistedftp import FTPServiceFactory45from txpkgupload.twistedftp import FTPServiceFactory
46from txpkgupload.twistedsftp import SFTPServer46from txpkgupload.twistedsftp import (
47 PkgUploadFileTransferServer,
48 SFTPServer,
49 )
4750
4851
49# Ensure that formencode does not translate strings; there are encoding issues52# Ensure that formencode does not translate strings; there are encoding issues
@@ -155,6 +158,7 @@
155 LaunchpadAvatar.__init__(self, user_dict)158 LaunchpadAvatar.__init__(self, user_dict)
156 self.fs_root = fs_root159 self.fs_root = fs_root
157 self.temp_dir = temp_dir160 self.temp_dir = temp_dir
161 self.subsystemLookup["sftp"] = PkgUploadFileTransferServer
158162
159163
160class Realm:164class Realm:
161165
=== modified file 'src/txpkgupload/twistedsftp.py'
--- src/txpkgupload/twistedsftp.py 2015-01-21 12:59:40 +0000
+++ src/txpkgupload/twistedsftp.py 2015-01-22 11:33:13 +0000
@@ -13,16 +13,14 @@
13import os13import os
14import tempfile14import tempfile
1515
16from lazr.sshserver.events import SFTPClosed16from lazr.sshserver.sftp import (
17from lazr.sshserver.sftp import FileIsADirectory17 FileIsADirectory,
18 FileTransferServer,
19 )
18from twisted.conch.interfaces import (20from twisted.conch.interfaces import (
19 ISFTPFile,21 ISFTPFile,
20 ISFTPServer,22 ISFTPServer,
21 )23 )
22from zope.component import (
23 adapter,
24 provideHandler,
25 )
26from zope.interface import implements24from zope.interface import implements
2725
28from txpkgupload.filesystem import UploadFileSystem26from txpkgupload.filesystem import UploadFileSystem
@@ -35,15 +33,12 @@
35 implements(ISFTPServer)33 implements(ISFTPServer)
3634
37 def __init__(self, avatar):35 def __init__(self, avatar):
38 provideHandler(self.connectionClosed)
39 self._avatar = avatar36 self._avatar = avatar
40 self._fs_root = avatar.fs_root37 self._fs_root = avatar.fs_root
41 self.uploadfilesystem = UploadFileSystem(38 self.uploadfilesystem = UploadFileSystem(
42 tempfile.mkdtemp(dir=avatar.temp_dir))39 tempfile.mkdtemp(dir=avatar.temp_dir))
43 self._current_upload = self.uploadfilesystem.rootpath40 self._current_upload = self.uploadfilesystem.rootpath
44 os.chmod(self._current_upload, 0770)41 os.chmod(self._current_upload, 0770)
45 self.hook = Hooks(self._fs_root, perms='g+rws', prefix='-sftp')
46 self.hook.new_client_hook(self._current_upload, 0, 0)
4742
48 def gotVersion(self, other_version, ext_data):43 def gotVersion(self, other_version, ext_data):
49 return {}44 return {}
@@ -101,12 +96,6 @@
101 return self.uploadfilesystem._full(96 return self.uploadfilesystem._full(
102 self.uploadfilesystem._sanitize(filename))97 self.uploadfilesystem._sanitize(filename))
10398
104 @adapter(SFTPClosed)
105 def connectionClosed(self, event):
106 if event.avatar is not self._avatar:
107 return
108 self.hook.client_done_hook(self._current_upload, 0, 0)
109
11099
111class SFTPFile:100class SFTPFile:
112101
@@ -138,3 +127,16 @@
138127
139 def setAttrs(self, attr):128 def setAttrs(self, attr):
140 pass129 pass
130
131
132class PkgUploadFileTransferServer(FileTransferServer):
133
134 def __init__(self, data=None, avatar=None):
135 FileTransferServer.__init__(self, data=data, avatar=avatar)
136 self.hook = Hooks(self.client._fs_root, perms='g+rws', prefix='-sftp')
137 self.hook.new_client_hook(self.client._current_upload, 0, 0)
138
139 def connectionLost(self, reason):
140 if self.hook is not None:
141 self.hook.client_done_hook(self.client._current_upload, 0, 0)
142 self.hook = None

Subscribers

People subscribed via source and target branches

to all changes: