Skip to content

Commit

Permalink
Add speed limiting option for uploads
Browse files Browse the repository at this point in the history
  • Loading branch information
joelw committed Mar 2, 2012
1 parent 0151fa4 commit 3a64621
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 1 deletion.
1 change: 1 addition & 0 deletions S3/Config.py
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ class Config(object):
website_index = "index.html" website_index = "index.html"
website_error = "" website_error = ""
website_endpoint = "http://%(bucket)s.s3-website-%(location)s.amazonaws.com/" website_endpoint = "http://%(bucket)s.s3-website-%(location)s.amazonaws.com/"
speed_limit = 0


## Creating a singleton ## Creating a singleton
def __new__(self, configfile = None): def __new__(self, configfile = None):
Expand Down
22 changes: 21 additions & 1 deletion S3/S3.py
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import logging import logging
import mimetypes import mimetypes
import re import re
import datetime
from logging import debug, info, warning, error from logging import debug, info, warning, error
from stat import ST_SIZE from stat import ST_SIZE


Expand Down Expand Up @@ -654,16 +655,35 @@ def send_file(self, request, file, labels, throttle = 0, retries = _max_retries,
file.seek(offset) file.seek(offset)
md5_hash = md5() md5_hash = md5()
try: try:
self.sleep_adjust = 0.0
while (size_left > 0): while (size_left > 0):
#debug("SendFile: Reading up to %d bytes from '%s'" % (self.config.send_chunk, file.name)) #debug("SendFile: Reading up to %d bytes from '%s'" % (self.config.send_chunk, file.name))
data = file.read(min(self.config.send_chunk, size_left)) sendsize = min(self.config.send_chunk, size_left)
data = file.read(sendsize)
md5_hash.update(data) md5_hash.update(data)
time_before = datetime.datetime.now()
conn.send(data) conn.send(data)
time_after = datetime.datetime.now()
elapsed_time = (time_after - time_before).total_seconds()
if self.config.progress_meter: if self.config.progress_meter:
progress.update(delta_position = len(data)) progress.update(delta_position = len(data))
size_left -= len(data) size_left -= len(data)
if throttle: if throttle:
time.sleep(throttle) time.sleep(throttle)
# Speed limit
if self.config.speed_limit > 0:
expected_time = float(sendsize) / (self.config.speed_limit*1024)
debug("sendsize %s, Expected %s, Actual %s", sendsize, expected_time, elapsed_time)
if expected_time > elapsed_time:
time_before = datetime.datetime.now()
time.sleep(expected_time - elapsed_time + self.sleep_adjust)
time_after = datetime.datetime.now()
self.sleep_adjust = (expected_time - elapsed_time) - (time_after - time_before).total_seconds()
debug("Sleep adjust %s", self.sleep_adjust)
if self.sleep_adjust > 0.5:
self.sleep_adjust = 0.5
if self.sleep_adjust < -0.5:
self.sleep_adjust = -0.5
md5_computed = md5_hash.hexdigest() md5_computed = md5_hash.hexdigest()
response = {} response = {}
http_response = conn.getresponse() http_response = conn.getresponse()
Expand Down
1 change: 1 addition & 0 deletions s3cmd
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -1548,6 +1548,7 @@ def main():
optparser.add_option("-d", "--debug", dest="verbosity", action="store_const", const=logging.DEBUG, help="Enable debug output.") optparser.add_option("-d", "--debug", dest="verbosity", action="store_const", const=logging.DEBUG, help="Enable debug output.")
optparser.add_option( "--version", dest="show_version", action="store_true", help="Show s3cmd version (%s) and exit." % (PkgInfo.version)) optparser.add_option( "--version", dest="show_version", action="store_true", help="Show s3cmd version (%s) and exit." % (PkgInfo.version))
optparser.add_option("-F", "--follow-symlinks", dest="follow_symlinks", action="store_true", default=False, help="Follow symbolic links as if they are regular files") optparser.add_option("-F", "--follow-symlinks", dest="follow_symlinks", action="store_true", default=False, help="Follow symbolic links as if they are regular files")
optparser.add_option( "--speedlimit", dest="speed_limit", action="store", metavar="SPEED", default=0, help="Limit transfer to SPEED KB/s")


optparser.set_usage(optparser.usage + " COMMAND [parameters]") optparser.set_usage(optparser.usage + " COMMAND [parameters]")
optparser.set_description('S3cmd is a tool for managing objects in '+ optparser.set_description('S3cmd is a tool for managing objects in '+
Expand Down

2 comments on commit 3a64621

@integritydc
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Excellent! This was what I needed to keep my server from slowing down while moving backups to Amazon. This still works in the latest version of s3cmd (1.5.0-beta1) although, obviously, the line numbers aren't current. Also since I'm using Python 2.6, total_seconds() was not available. Had to make a couple of modifications to calculate seconds since the function wasn't available. Thanks for your submission!

@joelw
Copy link
Owner Author

@joelw joelw commented on 3a64621 Mar 8, 2014

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm glad to hear it was useful! :) It seemed like a glaring omission to me as well.

From memory, when I wrote it s3cmd wasn't really being actively maintained and pull requests weren't being processed, but last time I checked the situation had changed. If you've got it working with the latest versions of s3cmd and Python, please consider submitting your patch!

Please sign in to comment.