prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Fuzzers page does not work well with large number of jobs
  For libFuzzer, if we have a lot of existing jobs (>100) and want to add a new job and associate it. Submit button feels stuck, does not show updates, and take 1-2 min to finish. Can we show some update or something better to optimize this when only one job is updated.
  
  @oliverchang as fyi.
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `src/python/fuzzing/fuzzer_selection.py`
  Content:
  ```
  1 # Copyright 2019 Google LLC
  2 #
  3 # Licensed under the Apache License, Version 2.0 (the "License");
  4 # you may not use this file except in compliance with the License.
  5 # You may obtain a copy of the License at
  6 #
  7 #      http://www.apache.org/licenses/LICENSE-2.0
  8 #
  9 # Unless required by applicable law or agreed to in writing, software
  10 # distributed under the License is distributed on an "AS IS" BASIS,
  11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12 # See the License for the specific language governing permissions and
  13 # limitations under the License.
  14 """Helper functions to update fuzzer-job mappings, and select fuzzers to run."""
  15 
  16 import collections
  17 
  18 from base import utils
  19 from datastore import data_types
  20 from datastore import fuzz_target_utils
  21 from datastore import ndb
  22 from datastore import ndb_utils
  23 from metrics import logs
  24 from system import environment
  25 
  26 # Used to prepare targets to be passed to utils.random_weighted_choice.
  27 WeightedTarget = collections.namedtuple('WeightedTarget', ['target', 'weight'])
  28 
  29 
  30 def update_mappings_for_fuzzer(fuzzer, mappings=None):
  31   """Clear existing mappings for a fuzzer, and replace them."""
  32   if mappings is None:
  33     mappings = fuzzer.jobs
  34 
  35   query = data_types.FuzzerJob.query()
  36   query = query.filter(data_types.FuzzerJob.fuzzer == fuzzer.name)
  37   entities = ndb_utils.get_all_from_query(query)
  38   old_mappings = {}
  39   for entity in entities:
  40     old_mappings[(entity.job, entity.platform)] = entity
  41 
  42   new_mappings = []
  43   for job_name in mappings:
  44     job = data_types.Job.query(data_types.Job.name == job_name).get()
  45     if not job:
  46       logs.log_error('An unknown job %s was selected for fuzzer %s.' %
  47                      (job_name, fuzzer.name))
  48       continue
  49 
  50     mapping = old_mappings.pop((job_name, job.platform), None)
  51     if mapping:
  52       continue
  53 
  54     mapping = data_types.FuzzerJob()
  55     mapping.fuzzer = fuzzer.name
  56     mapping.job = job_name
  57     mapping.platform = job.platform
  58     new_mappings.append(mapping)
  59 
  60   ndb.put_multi(new_mappings)
  61   ndb.delete_multi([m.key for m in list(old_mappings.values())])
  62 
  63 
  64 def update_platform_for_job(job_name, new_platform):
  65   """Update platform for all mappings for a particular job."""
  66   query = data_types.FuzzerJob.query()
  67   query = query.filter(data_types.FuzzerJob.job == job_name)
  68   mappings = ndb_utils.get_all_from_query(query)
  69   new_mappings = []
  70   for mapping in mappings:
  71     mapping.platform = new_platform
  72     new_mappings.append(mapping)
  73   ndb.put_multi(new_mappings)
  74 
  75 
  76 def get_fuzz_task_payload(platform=None):
  77   """Select a fuzzer that can run on this platform."""
  78   if not platform:
  79     queue_override = environment.get_value('QUEUE_OVERRIDE')
  80     platform = queue_override if queue_override else environment.platform()
  81 
  82   query = data_types.FuzzerJob.query()
  83   query = query.filter(data_types.FuzzerJob.platform == platform)
  84 
  85   mappings = list(ndb_utils.get_all_from_query(query))
  86   if not mappings:
  87     return None, None
  88 
  89   selection = utils.random_weighted_choice(mappings)
  90   return selection.fuzzer, selection.job
  91 
  92 
  93 def select_fuzz_target(targets, target_weights):
  94   """Select a fuzz target from a list of potential targets."""
  95   assert targets
  96 
  97   weighted_targets = []
  98   for target in targets:
  99     weight = target_weights.get(target, 1.0)
  100     weighted_targets.append(WeightedTarget(target, weight))
  101 
  102   return utils.random_weighted_choice(weighted_targets).target
  103 
  104 
  105 def get_fuzz_target_weights():
  106   """Get a list of fuzz target weights based on the current fuzzer."""
  107   job_type = environment.get_value('JOB_NAME')
  108 
  109   target_jobs = list(fuzz_target_utils.get_fuzz_target_jobs(job=job_type))
  110   fuzz_targets = fuzz_target_utils.get_fuzz_targets_for_target_jobs(target_jobs)
  111 
  112   weights = {}
  113   for fuzz_target, target_job in zip(fuzz_targets, target_jobs):
  114     if not fuzz_target:
  115       logs.log_error('Skipping weight assignment for fuzz target %s.' %
  116                      target_job.fuzz_target_name)
  117       continue
  118 
  119     weights[fuzz_target.binary] = target_job.weight
  120 
  121   return weights
  122
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/src/python/fuzzing/fuzzer_selection.py b/src/python/fuzzing/fuzzer_selection.py
  --- a/src/python/fuzzing/fuzzer_selection.py
  +++ b/src/python/fuzzing/fuzzer_selection.py
  @@ -37,20 +37,20 @@
     entities = ndb_utils.get_all_from_query(query)
     old_mappings = {}
     for entity in entities:
  -    old_mappings[(entity.job, entity.platform)] = entity
  +    old_mappings[entity.job] = entity
   
     new_mappings = []
     for job_name in mappings:
  +    mapping = old_mappings.pop(job_name, None)
  +    if mapping:
  +      continue
  +
       job = data_types.Job.query(data_types.Job.name == job_name).get()
       if not job:
         logs.log_error('An unknown job %s was selected for fuzzer %s.' %
                        (job_name, fuzzer.name))
         continue
   
  -    mapping = old_mappings.pop((job_name, job.platform), None)
  -    if mapping:
  -      continue
  -
       mapping = data_types.FuzzerJob()
       mapping.fuzzer = fuzzer.name
       mapping.job = job_name
  
verification_info: {"golden_diff": "diff --git a/src/python/fuzzing/fuzzer_selection.py b/src/python/fuzzing/fuzzer_selection.py\n--- a/src/python/fuzzing/fuzzer_selection.py\n+++ b/src/python/fuzzing/fuzzer_selection.py\n@@ -37,20 +37,20 @@\n   entities = ndb_utils.get_all_from_query(query)\n   old_mappings = {}\n   for entity in entities:\n-    old_mappings[(entity.job, entity.platform)] = entity\n+    old_mappings[entity.job] = entity\n \n   new_mappings = []\n   for job_name in mappings:\n+    mapping = old_mappings.pop(job_name, None)\n+    if mapping:\n+      continue\n+\n     job = data_types.Job.query(data_types.Job.name == job_name).get()\n     if not job:\n       logs.log_error('An unknown job %s was selected for fuzzer %s.' %\n                      (job_name, fuzzer.name))\n       continue\n \n-    mapping = old_mappings.pop((job_name, job.platform), None)\n-    if mapping:\n-      continue\n-\n     mapping = data_types.FuzzerJob()\n     mapping.fuzzer = fuzzer.name\n     mapping.job = job_name\n", "issue": "Fuzzers page does not work well with large number of jobs\nFor libFuzzer, if we have a lot of existing jobs (>100) and want to add a new job and associate it. Submit button feels stuck, does not show updates, and take 1-2 min to finish. Can we show some update or something better to optimize this when only one job is updated.\r\n\r\n@oliverchang as fyi.\n", "before_files": [{"content": "# Copyright 2019 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\"\"\"Helper functions to update fuzzer-job mappings, and select fuzzers to run.\"\"\"\n\nimport collections\n\nfrom base import utils\nfrom datastore import data_types\nfrom datastore import fuzz_target_utils\nfrom datastore import ndb\nfrom datastore import ndb_utils\nfrom metrics import logs\nfrom system import environment\n\n# Used to prepare targets to be passed to utils.random_weighted_choice.\nWeightedTarget = collections.namedtuple('WeightedTarget', ['target', 'weight'])\n\n\ndef update_mappings_for_fuzzer(fuzzer, mappings=None):\n  \"\"\"Clear existing mappings for a fuzzer, and replace them.\"\"\"\n  if mappings is None:\n    mappings = fuzzer.jobs\n\n  query = data_types.FuzzerJob.query()\n  query = query.filter(data_types.FuzzerJob.fuzzer == fuzzer.name)\n  entities = ndb_utils.get_all_from_query(query)\n  old_mappings = {}\n  for entity in entities:\n    old_mappings[(entity.job, entity.platform)] = entity\n\n  new_mappings = []\n  for job_name in mappings:\n    job = data_types.Job.query(data_types.Job.name == job_name).get()\n    if not job:\n      logs.log_error('An unknown job %s was selected for fuzzer %s.' %\n                     (job_name, fuzzer.name))\n      continue\n\n    mapping = old_mappings.pop((job_name, job.platform), None)\n    if mapping:\n      continue\n\n    mapping = data_types.FuzzerJob()\n    mapping.fuzzer = fuzzer.name\n    mapping.job = job_name\n    mapping.platform = job.platform\n    new_mappings.append(mapping)\n\n  ndb.put_multi(new_mappings)\n  ndb.delete_multi([m.key for m in list(old_mappings.values())])\n\n\ndef update_platform_for_job(job_name, new_platform):\n  \"\"\"Update platform for all mappings for a particular job.\"\"\"\n  query = data_types.FuzzerJob.query()\n  query = query.filter(data_types.FuzzerJob.job == job_name)\n  mappings = ndb_utils.get_all_from_query(query)\n  new_mappings = []\n  for mapping in mappings:\n    mapping.platform = new_platform\n    new_mappings.append(mapping)\n  ndb.put_multi(new_mappings)\n\n\ndef get_fuzz_task_payload(platform=None):\n  \"\"\"Select a fuzzer that can run on this platform.\"\"\"\n  if not platform:\n    queue_override = environment.get_value('QUEUE_OVERRIDE')\n    platform = queue_override if queue_override else environment.platform()\n\n  query = data_types.FuzzerJob.query()\n  query = query.filter(data_types.FuzzerJob.platform == platform)\n\n  mappings = list(ndb_utils.get_all_from_query(query))\n  if not mappings:\n    return None, None\n\n  selection = utils.random_weighted_choice(mappings)\n  return selection.fuzzer, selection.job\n\n\ndef select_fuzz_target(targets, target_weights):\n  \"\"\"Select a fuzz target from a list of potential targets.\"\"\"\n  assert targets\n\n  weighted_targets = []\n  for target in targets:\n    weight = target_weights.get(target, 1.0)\n    weighted_targets.append(WeightedTarget(target, weight))\n\n  return utils.random_weighted_choice(weighted_targets).target\n\n\ndef get_fuzz_target_weights():\n  \"\"\"Get a list of fuzz target weights based on the current fuzzer.\"\"\"\n  job_type = environment.get_value('JOB_NAME')\n\n  target_jobs = list(fuzz_target_utils.get_fuzz_target_jobs(job=job_type))\n  fuzz_targets = fuzz_target_utils.get_fuzz_targets_for_target_jobs(target_jobs)\n\n  weights = {}\n  for fuzz_target, target_job in zip(fuzz_targets, target_jobs):\n    if not fuzz_target:\n      logs.log_error('Skipping weight assignment for fuzz target %s.' %\n                     target_job.fuzz_target_name)\n      continue\n\n    weights[fuzz_target.binary] = target_job.weight\n\n  return weights\n", "path": "src/python/fuzzing/fuzzer_selection.py"}], "after_files": [{"content": "# Copyright 2019 Google LLC\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\"\"\"Helper functions to update fuzzer-job mappings, and select fuzzers to run.\"\"\"\n\nimport collections\n\nfrom base import utils\nfrom datastore import data_types\nfrom datastore import fuzz_target_utils\nfrom datastore import ndb\nfrom datastore import ndb_utils\nfrom metrics import logs\nfrom system import environment\n\n# Used to prepare targets to be passed to utils.random_weighted_choice.\nWeightedTarget = collections.namedtuple('WeightedTarget', ['target', 'weight'])\n\n\ndef update_mappings_for_fuzzer(fuzzer, mappings=None):\n  \"\"\"Clear existing mappings for a fuzzer, and replace them.\"\"\"\n  if mappings is None:\n    mappings = fuzzer.jobs\n\n  query = data_types.FuzzerJob.query()\n  query = query.filter(data_types.FuzzerJob.fuzzer == fuzzer.name)\n  entities = ndb_utils.get_all_from_query(query)\n  old_mappings = {}\n  for entity in entities:\n    old_mappings[entity.job] = entity\n\n  new_mappings = []\n  for job_name in mappings:\n    mapping = old_mappings.pop(job_name, None)\n    if mapping:\n      continue\n\n    job = data_types.Job.query(data_types.Job.name == job_name).get()\n    if not job:\n      logs.log_error('An unknown job %s was selected for fuzzer %s.' %\n                     (job_name, fuzzer.name))\n      continue\n\n    mapping = data_types.FuzzerJob()\n    mapping.fuzzer = fuzzer.name\n    mapping.job = job_name\n    mapping.platform = job.platform\n    new_mappings.append(mapping)\n\n  ndb.put_multi(new_mappings)\n  ndb.delete_multi([m.key for m in list(old_mappings.values())])\n\n\ndef update_platform_for_job(job_name, new_platform):\n  \"\"\"Update platform for all mappings for a particular job.\"\"\"\n  query = data_types.FuzzerJob.query()\n  query = query.filter(data_types.FuzzerJob.job == job_name)\n  mappings = ndb_utils.get_all_from_query(query)\n  new_mappings = []\n  for mapping in mappings:\n    mapping.platform = new_platform\n    new_mappings.append(mapping)\n  ndb.put_multi(new_mappings)\n\n\ndef get_fuzz_task_payload(platform=None):\n  \"\"\"Select a fuzzer that can run on this platform.\"\"\"\n  if not platform:\n    queue_override = environment.get_value('QUEUE_OVERRIDE')\n    platform = queue_override if queue_override else environment.platform()\n\n  query = data_types.FuzzerJob.query()\n  query = query.filter(data_types.FuzzerJob.platform == platform)\n\n  mappings = list(ndb_utils.get_all_from_query(query))\n  if not mappings:\n    return None, None\n\n  selection = utils.random_weighted_choice(mappings)\n  return selection.fuzzer, selection.job\n\n\ndef select_fuzz_target(targets, target_weights):\n  \"\"\"Select a fuzz target from a list of potential targets.\"\"\"\n  assert targets\n\n  weighted_targets = []\n  for target in targets:\n    weight = target_weights.get(target, 1.0)\n    weighted_targets.append(WeightedTarget(target, weight))\n\n  return utils.random_weighted_choice(weighted_targets).target\n\n\ndef get_fuzz_target_weights():\n  \"\"\"Get a list of fuzz target weights based on the current fuzzer.\"\"\"\n  job_type = environment.get_value('JOB_NAME')\n\n  target_jobs = list(fuzz_target_utils.get_fuzz_target_jobs(job=job_type))\n  fuzz_targets = fuzz_target_utils.get_fuzz_targets_for_target_jobs(target_jobs)\n\n  weights = {}\n  for fuzz_target, target_job in zip(fuzz_targets, target_jobs):\n    if not fuzz_target:\n      logs.log_error('Skipping weight assignment for fuzz target %s.' %\n                     target_job.fuzz_target_name)\n      continue\n\n    weights[fuzz_target.binary] = target_job.weight\n\n  return weights\n", "path": "src/python/fuzzing/fuzzer_selection.py"}]}