~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/transport/sftp.py

  • Committer: John Arbash Meinel
  • Date: 2006-08-18 22:52:19 UTC
  • mfrom: (1711.2.134 sftp-benchmarks)
  • mto: This revision was merged to the branch mainline in revision 1989.
  • Revision ID: john@arbash-meinel.com-20060818225219-6f4bfa3870d716b7
[merge] sftp benchmarks

Show diffs side-by-side

added added

removed removed

Lines of Context:
1136
1136
                        x)
1137
1137
 
1138
1138
 
 
1139
class SocketDelay(object):
 
1140
    """A socket decorator to make TCP appear slower.
 
1141
 
 
1142
    This changes recv, send, and sendall to add a fixed latency to each python
 
1143
    call if a new roundtrip is detected. That is, when a recv is called and the
 
1144
    flag new_roundtrip is set, latency is charged. Every send and send_all
 
1145
    sets this flag.
 
1146
 
 
1147
    In addition every send, sendall and recv sleeps a bit per character send to
 
1148
    simulate bandwidth.
 
1149
 
 
1150
    Not all methods are implemented, this is deliberate as this class is not a
 
1151
    replacement for the builtin sockets layer. fileno is not implemented to
 
1152
    prevent the proxy being bypassed. 
 
1153
    """
 
1154
 
 
1155
    simulated_time = 0
 
1156
    _proxied_arguments = dict.fromkeys([
 
1157
        "close", "getpeername", "getsockname", "getsockopt", "gettimeout",
 
1158
        "setblocking", "setsockopt", "settimeout", "shutdown"])
 
1159
 
 
1160
    def __init__(self, sock, latency, bandwidth=1.0, 
 
1161
                 really_sleep=True):
 
1162
        """ 
 
1163
        :param bandwith: simulated bandwith (MegaBit)
 
1164
        :param really_sleep: If set to false, the SocketDelay will just
 
1165
        increase a counter, instead of calling time.sleep. This is useful for
 
1166
        unittesting the SocketDelay.
 
1167
        """
 
1168
        self.sock = sock
 
1169
        self.latency = latency
 
1170
        self.really_sleep = really_sleep
 
1171
        self.time_per_byte = 1 / (bandwidth / 8.0 * 1024 * 1024) 
 
1172
        self.new_roundtrip = False
 
1173
 
 
1174
    def sleep(self, s):
 
1175
        if self.really_sleep:
 
1176
            time.sleep(s)
 
1177
        else:
 
1178
            SocketDelay.simulated_time += s
 
1179
 
 
1180
    def __getattr__(self, attr):
 
1181
        if attr in SocketDelay._proxied_arguments:
 
1182
            return getattr(self.sock, attr)
 
1183
        raise AttributeError("'SocketDelay' object has no attribute %r" %
 
1184
                             attr)
 
1185
 
 
1186
    def dup(self):
 
1187
        return SocketDelay(self.sock.dup(), self.latency, self.time_per_byte,
 
1188
                           self._sleep)
 
1189
 
 
1190
    def recv(self, *args):
 
1191
        data = self.sock.recv(*args)
 
1192
        if data and self.new_roundtrip:
 
1193
            self.new_roundtrip = False
 
1194
            self.sleep(self.latency)
 
1195
        self.sleep(len(data) * self.time_per_byte)
 
1196
        return data
 
1197
 
 
1198
    def sendall(self, data, flags=0):
 
1199
        if not self.new_roundtrip:
 
1200
            self.new_roundtrip = True
 
1201
            self.sleep(self.latency)
 
1202
        self.sleep(len(data) * self.time_per_byte)
 
1203
        return self.sock.sendall(data, flags)
 
1204
 
 
1205
    def send(self, data, flags=0):
 
1206
        if not self.new_roundtrip:
 
1207
            self.new_roundtrip = True
 
1208
            self.sleep(self.latency)
 
1209
        bytes_sent = self.sock.send(data, flags)
 
1210
        self.sleep(bytes_sent * self.time_per_byte)
 
1211
        return bytes_sent
 
1212
 
 
1213
 
1139
1214
class SFTPServer(Server):
1140
1215
    """Common code for SFTP server facilities."""
1141
1216
 
1148
1223
        self._vendor = 'none'
1149
1224
        # sftp server logs
1150
1225
        self.logs = []
 
1226
        self.add_latency = 0
1151
1227
 
1152
1228
    def _get_sftp_url(self, path):
1153
1229
        """Calculate an sftp url to this server for path."""
1157
1233
        """StubServer uses this to log when a new server is created."""
1158
1234
        self.logs.append(message)
1159
1235
 
 
1236
    def _run_server_entry(self, sock):
 
1237
        """Entry point for all implementations of _run_server.
 
1238
        
 
1239
        If self.add_latency is > 0.000001 then sock is given a latency adding
 
1240
        decorator.
 
1241
        """
 
1242
        if self.add_latency > 0.000001:
 
1243
            sock = SocketDelay(sock, self.add_latency)
 
1244
        return self._run_server(sock)
 
1245
 
1160
1246
    def _run_server(self, s):
1161
1247
        ssh_server = paramiko.Transport(s)
1162
1248
        key_file = pathjoin(self._homedir, 'test_rsa.key')
1188
1274
        self._root = '/'
1189
1275
        if sys.platform == 'win32':
1190
1276
            self._root = ''
1191
 
        self._listener = SocketListener(self._run_server)
 
1277
        self._listener = SocketListener(self._run_server_entry)
1192
1278
        self._listener.setDaemon(True)
1193
1279
        self._listener.start()
1194
1280