Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1883)

Unified Diff: appengine/swarming/server/bot_code.py

Issue 2953253003: Replace custom blob gRPC API with ByteStream (Closed)
Patch Set: Rebase to latest Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: appengine/swarming/server/bot_code.py
diff --git a/appengine/swarming/server/bot_code.py b/appengine/swarming/server/bot_code.py
index 81a56e0d7ad39fbc51469174e872f37d4705ad7a..a346c1ae200829cf309a5c8443837d6b6699e6af 100644
--- a/appengine/swarming/server/bot_code.py
+++ b/appengine/swarming/server/bot_code.py
@@ -28,6 +28,7 @@ from server import config as local_config
ROOT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+MAX_MEMCACHED_SIZE_BYTES = 1000000
Vadim Sh. 2017/06/23 18:26:50 how many parts do we get?
aludwin 2017/06/26 17:12:56 Two currently - though in the unit test, we get 11
### Models.
@@ -222,7 +223,7 @@ def get_swarming_bot_zip(host):
A string representing the zipped file's contents.
"""
version, additionals = get_bot_version(host)
- content = memcache.get('code-' + version, namespace='bot_code')
+ content = get_cached_swarming_bot_zip(version)
if content:
logging.debug('memcached bot code %s; %d bytes', version, len(content))
return content
@@ -236,11 +237,71 @@ def get_swarming_bot_zip(host):
content, version = bot_archive.get_swarming_bot_zip(
bot_dir, host, utils.get_app_version(), additionals,
local_config.settings().enable_ts_monitoring)
- # This is immutable so not no need to set expiration time.
- memcache.set('code-' + version, content, namespace='bot_code')
logging.info('generated bot code %s; %d bytes', version, len(content))
+ cache_swarming_bot_zip(version, content)
return content
Vadim Sh. 2017/06/23 18:26:50 nit: \n (two blank lines between top-level code un
aludwin 2017/06/26 17:12:56 Done.
+class MemcacheMissingException(Exception):
+ pass
+
Vadim Sh. 2017/06/23 18:26:50 nit: \n
aludwin 2017/06/26 17:12:56 Done.
+def get_cached_swarming_bot_zip(version):
+ """Returns the bot contents if its been cached, or None if missing."""
+ try:
+ num_parts = get_cached_bot_entry(version, 'parts')
Vadim Sh. 2017/06/23 18:26:50 'parts' and 'signature' should be part of one memc
aludwin 2017/06/26 17:12:56 Done.
aludwin 2017/06/26 17:12:56 Done.
+ true_sig = get_cached_bot_entry(version, 'signature')
+ content = ''
+ for p in range(0, num_parts):
+ content += get_cached_bot_entry(version, 'content', p)
Vadim Sh. 2017/06/23 18:26:50 please use asynchronous memcache API to fetch part
aludwin 2017/06/26 17:12:56 Done.
+ h = hashlib.sha256()
+ h.update(content)
+ if h.hexdigest() != true_sig:
+ logging.error('bot %s had signature %s instead of expected %s', version,
+ h.hexdigest(), true_sig)
+ return None
+ return content
+ except MemcacheMissingException:
+ return None
+
+
+def cache_swarming_bot_zip(version, content):
+ """Caches the bot code to memcache."""
+ h = hashlib.sha256()
+ h.update(content)
+ p = 0
+ while len(content) > 0:
Vadim Sh. 2017/06/23 18:26:50 same here, it should be done in parallel
aludwin 2017/06/26 17:12:56 Done.
+ chunk_size = min(MAX_MEMCACHED_SIZE_BYTES, len(content))
+ set_cached_bot_entry(content[0:chunk_size], version, 'content', p)
+ content=content[chunk_size:]
+ p += 1
+ set_cached_bot_entry(h.hexdigest(), version, 'signature')
+ set_cached_bot_entry(p, version, 'parts')
+ logging.info('bot %s with sig %s saved in memcached in %d chunks',
+ version, h.hexdigest(), p)
+
+
+def get_cached_bot_entry(version, desc, part=None):
+ """Gets a bot entry from memcached.
+
+ Raise MemcacheMissingException if the entry is None.
+ """
+ res = memcache.get(cached_bot_key(version, desc, part), namespace='bot_code')
+ if res is None:
+ raise MemcacheMissingException()
+ return res
+
+
+def set_cached_bot_entry(content, version, desc, part=None):
+ """Sets a bot entry in memcached."""
+ memcache.set(cached_bot_key(version, desc, part), content,
+ namespace='bot_code')
+
+
+def cached_bot_key(version, desc, part):
+ """Returns a memcache key for bot entries."""
+ key = 'code-%s-%s' % (version, desc)
+ if part is not None:
+ key = '%s-%d' % (key, part)
+ return key
Vadim Sh. 2017/06/23 18:26:50 nit: \n
aludwin 2017/06/26 17:12:56 Missed this one but checked in locally for next up
### Bootstrap token.

Powered by Google App Engine
This is Rietveld 408576698