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

Side by Side Diff: dashboard/dashboard/graph_revisions.py

Issue 2748953003: . Base URL: https://github.com/catapult-project/catapult.git@master
Patch Set: Created 3 years, 9 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 unified diff | Download patch
« no previous file with comments | « dashboard/dashboard/common/stored_object.py ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 # Copyright 2015 The Chromium Authors. All rights reserved. 1 # Copyright 2015 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be 2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file. 3 # found in the LICENSE file.
4 4
5 """Handler to serve a simple time series for all points in a series. 5 """Handler to serve a simple time series for all points in a series.
6 6
7 This is used to show the revision slider for a chart; it includes data 7 This is used to show the revision slider for a chart; it includes data
8 for all past points, including those that are not recent. Each entry 8 for all past points, including those that are not recent. Each entry
9 in the returned list is a 3-item list: [revision, value, timestamp]. 9 in the returned list is a 3-item list: [revision, value, timestamp].
10 The revisions and values are used to plot a mini-chart, and the timestamps 10 The revisions and values are used to plot a mini-chart, and the timestamps
11 are used to label this mini-chart with dates. 11 are used to label this mini-chart with dates.
12 12
13 This list is cached, since querying all Row entities for a given test takes a 13 This list is cached, since querying all Row entities for a given test takes a
14 long time. This module also provides a function for updating the cache. 14 long time. This module also provides a function for updating the cache.
15 """ 15 """
16 16
17 import bisect 17 import bisect
18 import json 18 import json
19 19
20 from google.appengine.ext import ndb
21
20 from dashboard.common import datastore_hooks 22 from dashboard.common import datastore_hooks
21 from dashboard.common import namespaced_stored_object 23 from dashboard.common import namespaced_stored_object
22 from dashboard.common import request_handler 24 from dashboard.common import request_handler
23 from dashboard.common import utils 25 from dashboard.common import utils
24 from dashboard.models import graph_data 26 from dashboard.models import graph_data
25 27
26 _CACHE_KEY = 'num_revisions_%s' 28 _CACHE_KEY = 'num_revisions_%s'
27 29
28 30
29 class GraphRevisionsHandler(request_handler.RequestHandler): 31 class GraphRevisionsHandler(request_handler.RequestHandler):
30 """URL endpoint to list all the revisions for each test, for x-axis slider.""" 32 """URL endpoint to list all the revisions for each test, for x-axis slider."""
31 33
32 def post(self): 34 def post(self):
33 """Fetches a list of revisions and values for a given test. 35 """Fetches a list of revisions and values for a given test.
34 36
35 Request parameters: 37 Request parameters:
36 test_path: Full test path for a TestMetadata entity. 38 test_path: Full test path for a TestMetadata entity.
37 39
38 Outputs: 40 Outputs:
39 A JSON list of 3-item lists [revision, value, timestamp]. 41 A JSON list of 3-item lists [revision, value, timestamp].
40 """ 42 """
41 test_path = self.request.get('test_path') 43 test_path = self.request.get('test_path')
42 rows = namespaced_stored_object.Get(_CACHE_KEY % test_path) 44 rows = namespaced_stored_object.Get(_CACHE_KEY % test_path)
43 if not rows: 45 if not rows:
44 rows = _UpdateCache(utils.TestKey(test_path)) 46 rows = _UpdateCache(utils.TestKey(test_path))
45 self.response.out.write(json.dumps(rows)) 47 self.response.out.write(json.dumps(rows))
46 48
47 49
50 @ndb.synctasklet
48 def SetCache(test_path, rows): 51 def SetCache(test_path, rows):
49 """Sets the saved graph revisions data for a test. 52 """Sets the saved graph revisions data for a test.
50 53
51 Args: 54 Args:
52 test_path: A test path string. 55 test_path: A test path string.
53 rows: A list of [revision, value, timestamp] triplets. 56 rows: A list of [revision, value, timestamp] triplets.
54 """ 57 """
58 yield SetCacheAsync(test_path, rows)
59
60
61 @ndb.tasklet
62 def SetCacheAsync(test_path, rows):
55 # This first set generally only sets the internal-only cache. 63 # This first set generally only sets the internal-only cache.
56 namespaced_stored_object.Set(_CACHE_KEY % test_path, rows) 64 futures = [namespaced_stored_object.SetAsync(_CACHE_KEY % test_path, rows)]
57 65
58 # If this is an internal_only query for externally available data, 66 # If this is an internal_only query for externally available data,
59 # set the cache for that too. 67 # set the cache for that too.
60 if datastore_hooks.IsUnalteredQueryPermitted(): 68 if datastore_hooks.IsUnalteredQueryPermitted():
61 test = utils.TestKey(test_path).get() 69 test = utils.TestKey(test_path).get()
62 if test and not test.internal_only: 70 if test and not test.internal_only:
63 namespaced_stored_object.SetExternal(_CACHE_KEY % test_path, rows) 71 futures.append(
72 namespaced_stored_object.SetExternalAsync(
73 _CACHE_KEY % test_path, rows))
74 yield futures
64 75
65 76
66 def DeleteCache(test_path): 77 def DeleteCache(test_path):
67 """Removes any saved data for the given path.""" 78 """Removes any saved data for the given path."""
68 namespaced_stored_object.Delete(_CACHE_KEY % test_path) 79 namespaced_stored_object.Delete(_CACHE_KEY % test_path)
69 80
70 81
71 def _UpdateCache(test_key): 82 def _UpdateCache(test_key):
72 """Queries Rows for a test then updates the cache. 83 """Queries Rows for a test then updates the cache.
73 84
(...skipping 23 matching lines...) Expand all
97 SetCache(utils.TestPath(test_key), rows) 108 SetCache(utils.TestPath(test_key), rows)
98 return rows 109 return rows
99 110
100 111
101 def _MakeTriplet(row): 112 def _MakeTriplet(row):
102 """Makes a 3-item list of revision, value and timestamp for a Row.""" 113 """Makes a 3-item list of revision, value and timestamp for a Row."""
103 timestamp = utils.TimestampMilliseconds(row.timestamp) 114 timestamp = utils.TimestampMilliseconds(row.timestamp)
104 return [row.revision, row.value, timestamp] 115 return [row.revision, row.value, timestamp]
105 116
106 117
118 @ndb.synctasklet
107 def AddRowsToCache(row_entities): 119 def AddRowsToCache(row_entities):
108 """Adds a list of rows to the cache, in revision order. 120 """Adds a list of rows to the cache, in revision order.
109 121
110 Updates multiple cache entries for different tests. 122 Updates multiple cache entries for different tests.
111 123
112 Args: 124 Args:
113 row_entities: List of Row entities. 125 row_entities: List of Row entities.
114 """ 126 """
127 test_key_to_futures = {}
128 for row in row_entities:
129 test_key = row.parent_test
130 if test_key in test_key_to_futures:
131 continue
132
133 test_path = utils.TestPath(test_key)
134 test_key_to_futures[test_key] = namespaced_stored_object.GetAsync(
135 _CACHE_KEY % test_path)
136
137 yield test_key_to_futures.values()
138
115 test_key_to_rows = {} 139 test_key_to_rows = {}
116 for row in row_entities: 140 for row in row_entities:
117 test_key = row.parent_test 141 test_key = row.parent_test
118 if test_key in test_key_to_rows: 142 if test_key in test_key_to_rows:
119 graph_rows = test_key_to_rows[test_key] 143 graph_rows = test_key_to_rows[test_key]
120 else: 144 else:
121 test_path = utils.TestPath(test_key) 145 test_path = utils.TestPath(test_key)
122 graph_rows = namespaced_stored_object.Get(_CACHE_KEY % test_path) 146 graph_rows_future = test_key_to_futures.get(test_key)
147 graph_rows = graph_rows_future.get_result()
123 if not graph_rows: 148 if not graph_rows:
124 # We only want to update caches for tests that people have looked at. 149 # We only want to update caches for tests that people have looked at.
125 continue 150 continue
126 test_key_to_rows[test_key] = graph_rows 151 test_key_to_rows[test_key] = graph_rows
127 152
128 revisions = [r[0] for r in graph_rows] 153 revisions = [r[0] for r in graph_rows]
129 index = bisect.bisect_left(revisions, row.revision) 154 index = bisect.bisect_left(revisions, row.revision)
130 if index < len(revisions) - 1: 155 if index < len(revisions) - 1:
131 if revisions[index + 1] == row.revision: 156 if revisions[index + 1] == row.revision:
132 return # Already in cache. 157 return # Already in cache.
133 graph_rows.insert(index, _MakeTriplet(row)) 158 graph_rows.insert(index, _MakeTriplet(row))
134 159
160 futures = []
135 for test_key in test_key_to_rows: 161 for test_key in test_key_to_rows:
136 graph_rows = test_key_to_rows[test_key] 162 graph_rows = test_key_to_rows[test_key]
137 SetCache(utils.TestPath(test_key), graph_rows) 163 futures.append(SetCacheAsync(utils.TestPath(test_key), graph_rows))
164 yield futures
OLDNEW
« no previous file with comments | « dashboard/dashboard/common/stored_object.py ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698