| Index: appengine/auth_service/config.py
 | 
| diff --git a/appengine/auth_service/config.py b/appengine/auth_service/config.py
 | 
| index d387f205813ddb0c448feca8cb96edc162342e7f..f07b352cd7ab1083c2d445a6e6e94185fccf6a0b 100644
 | 
| --- a/appengine/auth_service/config.py
 | 
| +++ b/appengine/auth_service/config.py
 | 
| @@ -34,7 +34,6 @@ from components import utils
 | 
|  from components.auth import ipaddr
 | 
|  from components.auth import model
 | 
|  from components.config import validation
 | 
| -from components.config import validation_context
 | 
|  
 | 
|  from proto import config_pb2
 | 
|  import importer
 | 
| @@ -68,10 +67,17 @@ def get_remote_url():
 | 
|    return None
 | 
|  
 | 
|  
 | 
| -def get_config_revision(path):
 | 
| +def get_revisions():
 | 
| +  """Returns a mapping {config file name => Revision instance or None}."""
 | 
| +  futures = {p: _get_config_revision_async(p) for p in _CONFIG_SCHEMAS}
 | 
| +  return {p: f.get_result() for p, f in futures.iteritems()}
 | 
| +
 | 
| +
 | 
| +def _get_config_revision_async(path):
 | 
|    """Returns tuple with info about last imported config revision."""
 | 
| +  assert path in _CONFIG_SCHEMAS, path
 | 
|    schema = _CONFIG_SCHEMAS.get(path)
 | 
| -  return schema['revision_getter']() if schema else None
 | 
| +  return schema['revision_getter']()
 | 
|  
 | 
|  
 | 
|  @utils.cache_with_expiration(expiration_sec=60)
 | 
| @@ -115,7 +121,7 @@ def refetch_config(force=False):
 | 
|    dirty_in_authdb = {}
 | 
|    for path, (new_rev, conf) in sorted(configs.iteritems()):
 | 
|      assert path in _CONFIG_SCHEMAS, path
 | 
| -    cur_rev = get_config_revision(path)
 | 
| +    cur_rev = _get_config_revision_async(path).get_result()
 | 
|      if cur_rev != new_rev or force:
 | 
|        if _CONFIG_SCHEMAS[path]['use_authdb_transaction']:
 | 
|          dirty_in_authdb[path] = (new_rev, conf)
 | 
| @@ -193,10 +199,11 @@ class _AuthServiceConfig(ndb.Model):
 | 
|    url = ndb.StringProperty(indexed=False)
 | 
|  
 | 
|  
 | 
| -def _get_service_config_rev(cfg_name):
 | 
| +@ndb.tasklet
 | 
| +def _get_service_config_rev_async(cfg_name):
 | 
|    """Returns last processed Revision of given config."""
 | 
| -  e = _AuthServiceConfig.get_by_id(cfg_name)
 | 
| -  return Revision(e.revision, e.url) if e else None
 | 
| +  e = yield _AuthServiceConfig.get_by_id_async(cfg_name)
 | 
| +  raise ndb.Return(Revision(e.revision, e.url) if e else None)
 | 
|  
 | 
|  
 | 
|  def _get_service_config(cfg_name):
 | 
| @@ -222,13 +229,14 @@ def _update_service_config(cfg_name, rev, conf):
 | 
|  ### Group importer config implementation details.
 | 
|  
 | 
|  
 | 
| -def _get_imports_config_revision():
 | 
| +@ndb.tasklet
 | 
| +def _get_imports_config_revision_async():
 | 
|    """Returns Revision of last processed imports.cfg config."""
 | 
| -  e = importer.config_key().get()
 | 
| +  e = yield importer.config_key().get_async()
 | 
|    if not e or not isinstance(e.config_revision, dict):
 | 
| -    return None
 | 
| +    raise ndb.Return(None)
 | 
|    desc = e.config_revision
 | 
| -  return Revision(desc.get('rev'), desc.get('url'))
 | 
| +  raise ndb.Return(Revision(desc.get('rev'), desc.get('url')))
 | 
|  
 | 
|  
 | 
|  def _update_imports_config(rev, conf):
 | 
| @@ -255,15 +263,16 @@ def _imported_config_revisions_key():
 | 
|    return ndb.Key(_ImportedConfigRevisions, 'self', parent=model.root_key())
 | 
|  
 | 
|  
 | 
| -def _get_authdb_config_rev(path):
 | 
| +@ndb.tasklet
 | 
| +def _get_authdb_config_rev_async(path):
 | 
|    """Returns Revision of last processed config given its name."""
 | 
| -  mapping = _imported_config_revisions_key().get()
 | 
| +  mapping = yield _imported_config_revisions_key().get_async()
 | 
|    if not mapping or not isinstance(mapping.revisions, dict):
 | 
| -    return None
 | 
| +    raise ndb.Return(None)
 | 
|    desc = mapping.revisions.get(path)
 | 
|    if not isinstance(desc, dict):
 | 
| -    return None
 | 
| -  return Revision(desc.get('rev'), desc.get('url'))
 | 
| +    raise ndb.Return(None)
 | 
| +  raise ndb.Return(Revision(desc.get('rev'), desc.get('url')))
 | 
|  
 | 
|  
 | 
|  @datastore_utils.transactional
 | 
| @@ -470,7 +479,7 @@ def _update_oauth_config(rev, conf):
 | 
|  
 | 
|  # Config file name -> {
 | 
|  #   'proto_class': protobuf class of the config or None to keep it as text,
 | 
| -#   'revision_getter': lambda: <latest imported Revision>,
 | 
| +#   'revision_getter': lambda: ndb.Future with <latest imported Revision>
 | 
|  #   'validator': lambda config: <raises ValueError on invalid format>
 | 
|  #   'updater': lambda rev, config: True if applied, False if not.
 | 
|  #   'use_authdb_transaction': True to call 'updater' in AuthDB transaction.
 | 
| @@ -479,26 +488,26 @@ def _update_oauth_config(rev, conf):
 | 
|  _CONFIG_SCHEMAS = {
 | 
|    'imports.cfg': {
 | 
|      'proto_class': None, # importer configs are stored as text
 | 
| -    'revision_getter': _get_imports_config_revision,
 | 
| +    'revision_getter': _get_imports_config_revision_async,
 | 
|      'updater': _update_imports_config,
 | 
|      'use_authdb_transaction': False,
 | 
|    },
 | 
|    'ip_whitelist.cfg': {
 | 
|      'proto_class': config_pb2.IPWhitelistConfig,
 | 
| -    'revision_getter': lambda: _get_authdb_config_rev('ip_whitelist.cfg'),
 | 
| +    'revision_getter': lambda: _get_authdb_config_rev_async('ip_whitelist.cfg'),
 | 
|      'updater': _update_ip_whitelist_config,
 | 
|      'use_authdb_transaction': True,
 | 
|    },
 | 
|    'oauth.cfg': {
 | 
|      'proto_class': config_pb2.OAuthConfig,
 | 
| -    'revision_getter': lambda: _get_authdb_config_rev('oauth.cfg'),
 | 
| +    'revision_getter': lambda: _get_authdb_config_rev_async('oauth.cfg'),
 | 
|      'updater': _update_oauth_config,
 | 
|      'use_authdb_transaction': True,
 | 
|    },
 | 
|    'settings.cfg': {
 | 
|      'proto_class': None, # settings are stored as text in datastore
 | 
|      'default': '',  # it's fine if config file is not there
 | 
| -    'revision_getter': lambda: _get_service_config_rev('settings.cfg'),
 | 
| +    'revision_getter': lambda: _get_service_config_rev_async('settings.cfg'),
 | 
|      'updater': lambda rev, c: _update_service_config('settings.cfg', rev, c),
 | 
|      'use_authdb_transaction': False,
 | 
|    },
 | 
| 
 |