diff options
author | Samuel Merritt <sam@swiftstack.com> | 2012-11-08 11:13:21 -0800 |
---|---|---|
committer | Samuel Merritt <sam@swiftstack.com> | 2012-11-08 11:13:21 -0800 |
commit | 2cf41b6b9fe4d3148d5f9720364a7ca71f4c264f (patch) | |
tree | cbc1f24edb25e39ed57f20ba72812892b01a6b54 | |
parent | 494979661be2cf1b89acc22a31cfd87b86bca44e (diff) | |
download | swift-bench-2cf41b6b9fe4d3148d5f9720364a7ca71f4c264f.tar.gz |
Make swift-bench use less memory with large object sizes.
Before, swift-bench would create a string of the right size and pass
that to [direct_]put_object. Uploading 5 GB objects w/concurrency of
4? Hope you've got a spare 20 GB of RAM in that machine.
Now it lazily generates chunks (of size 64 KiB) to send. In my limited
testing, this keeps RAM usage low while not impacting speed.
There's backwards-compatibility code in
direct_client.direct_put_object for any callers who are still passing
in strings. There aren't any such in Swift's codebase, though. All one
of those callers now pass an iterable.
Fixes bug 911925.
Change-Id: I40669fc00c7fb6699d8fb514e1be9b69436eca42
-rw-r--r-- | swift/common/bench.py | 40 |
1 files changed, 37 insertions, 3 deletions
diff --git a/swift/common/bench.py b/swift/common/bench.py index 089bfa2..7eef51a 100644 --- a/swift/common/bench.py +++ b/swift/common/bench.py @@ -70,6 +70,40 @@ def create_containers(logger, conf): _func_on_containers(logger, conf, 'put_concurrency', client.put_container) +class SourceFile(object): + """ + Iterable, file-like object to lazily emit a bunch of zeros in + reasonable-size chunks. + + swift.common.direct_client wants iterables, but swiftclient wants + file-like objects where hasattr(thing, 'read') is true. Therefore, + this class can do both. + """ + + def __init__(self, size, chunk_size=1024 * 64): + self.pos = 0 + self.size = size + self.chunk_size = chunk_size + + def __iter__(self): + return self + + def __len__(self): + return self.size + + def next(self): + if self.pos >= self.size: + raise StopIteration + chunk_size = min(self.size - self.pos, self.chunk_size) + yield '0' * chunk_size + self.pos += chunk_size + + def read(self, desired_size): + chunk_size = min(self.size - self.pos, desired_size) + self.pos += chunk_size + return '0' * chunk_size + + class ConnectionPool(eventlet.pools.Pool): def __init__(self, url, size): @@ -423,10 +457,10 @@ class BenchPUT(Bench): if self.object_sources: source = random.choice(self.files) elif self.upper_object_size > self.lower_object_size: - source = '0' * random.randint(self.lower_object_size, - self.upper_object_size) + source = SourceFile(random.randint(self.lower_object_size, + self.upper_object_size)) else: - source = '0' * self.object_size + source = SourceFile(self.object_size) device = random.choice(self.devices) partition = str(random.randint(1, 3000)) container_name = random.choice(self.containers) |