Merge "Optimize memory consumption in disagreement processing"
This commit is contained in:
@@ -14,6 +14,7 @@
|
||||
# limitations under the License.
|
||||
|
||||
import bisect
|
||||
import collections
|
||||
import copy
|
||||
import time
|
||||
|
||||
@@ -642,46 +643,61 @@ class RecordProcessor(object):
|
||||
if user['core'] != core_old:
|
||||
utils.store_user(self.runtime_storage_inst, user)
|
||||
|
||||
def _close_patch(self, cores, marks):
|
||||
if len(marks) < 2:
|
||||
return
|
||||
|
||||
core_mark = 0
|
||||
for mark in sorted(marks, key=lambda x: x['date'], reverse=True):
|
||||
|
||||
if core_mark == 0:
|
||||
if (mark['module'], mark['branch'], mark['user_id']) in cores:
|
||||
# mark is from core engineer
|
||||
core_mark = mark['value']
|
||||
continue
|
||||
|
||||
disagreement = ((core_mark != 0) and
|
||||
((core_mark < 0 < mark['value']) or
|
||||
(core_mark > 0 > mark['value'])))
|
||||
old_disagreement = mark.get('x')
|
||||
mark['x'] = disagreement
|
||||
if old_disagreement != disagreement:
|
||||
yield mark
|
||||
|
||||
def _update_marks_with_disagreement(self):
|
||||
LOG.debug('Process marks to find disagreements')
|
||||
|
||||
marks_per_patch = {}
|
||||
cores = set()
|
||||
for user in self.runtime_storage_inst.get_all_users():
|
||||
for (module, branch) in (user['core'] or []):
|
||||
cores.add((module, branch, user['user_id']))
|
||||
|
||||
# map from review_id to current patch and list of marks
|
||||
marks_per_patch = collections.defaultdict(
|
||||
lambda: {'patch_number': 0, 'marks': []})
|
||||
|
||||
for record in self.runtime_storage_inst.get_all_records():
|
||||
if record['record_type'] == 'mark' and record['type'] == 'CRVW':
|
||||
review_id = record['review_id']
|
||||
patch_number = record['patch']
|
||||
if (review_id, patch_number) in marks_per_patch:
|
||||
marks_per_patch[(review_id, patch_number)].append(record)
|
||||
else:
|
||||
marks_per_patch[(review_id, patch_number)] = [record]
|
||||
|
||||
cores = dict([(user['user_id'], user)
|
||||
for user in self.runtime_storage_inst.get_all_users()
|
||||
if user['core']])
|
||||
if review_id in marks_per_patch:
|
||||
# review is already seen, check if patch is newer
|
||||
if (marks_per_patch[review_id]['patch_number'] <
|
||||
patch_number):
|
||||
# the patch is new, close the current
|
||||
for processed in self._close_patch(
|
||||
cores, marks_per_patch[review_id]['marks']):
|
||||
yield processed
|
||||
del marks_per_patch[review_id]
|
||||
|
||||
for key, marks in six.iteritems(marks_per_patch):
|
||||
if len(marks) < 2:
|
||||
continue
|
||||
marks_per_patch[review_id]['patch_number'] = patch_number
|
||||
marks_per_patch[review_id]['marks'].append(record)
|
||||
|
||||
core_mark = 0
|
||||
for mark in sorted(marks, key=lambda x: x['date'], reverse=True):
|
||||
|
||||
if core_mark == 0:
|
||||
user_id = mark['user_id']
|
||||
if user_id in cores:
|
||||
user = cores[user_id]
|
||||
if (mark['module'], mark['branch']) in user['core']:
|
||||
# mark is from core engineer
|
||||
core_mark = mark['value']
|
||||
continue
|
||||
|
||||
disagreement = (core_mark != 0) and (
|
||||
(core_mark < 0 < mark['value']) or
|
||||
(core_mark > 0 > mark['value']))
|
||||
old_disagreement = mark.get('x')
|
||||
mark['x'] = disagreement
|
||||
if old_disagreement != disagreement:
|
||||
yield mark
|
||||
# purge the rest
|
||||
for marks_patch in marks_per_patch.values():
|
||||
for processed in self._close_patch(cores, marks_patch['marks']):
|
||||
yield processed
|
||||
|
||||
def update(self, release_index=None):
|
||||
self.runtime_storage_inst.set_records(
|
||||
|
||||
@@ -925,6 +925,7 @@ class TestRecordProcessor(testtools.TestCase):
|
||||
'createdOn': timestamp,
|
||||
'module': 'nova',
|
||||
'branch': 'master',
|
||||
'status': 'NEW',
|
||||
'patchSets': [
|
||||
{'number': '1',
|
||||
'revision': '4d8984e92910c37b7d101c1ae8c8283a2e6f4a76',
|
||||
@@ -936,7 +937,7 @@ class TestRecordProcessor(testtools.TestCase):
|
||||
'createdOn': timestamp,
|
||||
'approvals': [
|
||||
{'type': 'CRVW', 'description': 'Code Review',
|
||||
'value': '1', 'grantedOn': timestamp - 1,
|
||||
'value': '2', 'grantedOn': timestamp - 1,
|
||||
'by': {
|
||||
'name': 'Homer Simpson',
|
||||
'email': 'hsimpson@gmail.com',
|
||||
@@ -948,15 +949,57 @@ class TestRecordProcessor(testtools.TestCase):
|
||||
'email': 'john_doe@ibm.com',
|
||||
'username': 'john_doe'}}
|
||||
]
|
||||
}]}
|
||||
},
|
||||
{'number': '2',
|
||||
'revision': '4d8984e92910c37b7d101c1ae8c8283a2e6f4a76',
|
||||
'ref': 'refs/changes/16/58516/1',
|
||||
'uploader': {
|
||||
'name': 'Bill Smith',
|
||||
'email': 'bill@smith.to',
|
||||
'username': 'bsmith'},
|
||||
'createdOn': timestamp + 1,
|
||||
'approvals': [
|
||||
{'type': 'CRVW', 'description': 'Code Review',
|
||||
'value': '1', 'grantedOn': timestamp + 2,
|
||||
'by': {
|
||||
'name': 'Homer Simpson',
|
||||
'email': 'hsimpson@gmail.com',
|
||||
'username': 'homer'}},
|
||||
{'type': 'CRVW', 'description': 'Code Review',
|
||||
'value': '-1', 'grantedOn': timestamp + 3,
|
||||
'by': {
|
||||
'name': 'Bart Simpson',
|
||||
'email': 'bsimpson@gmail.com',
|
||||
'username': 'bart'}},
|
||||
{'type': 'CRVW', 'description': 'Code Review',
|
||||
'value': '2', 'grantedOn': timestamp + 4,
|
||||
'by': {
|
||||
'name': 'John Doe',
|
||||
'email': 'john_doe@ibm.com',
|
||||
'username': 'john_doe'}}
|
||||
]
|
||||
}
|
||||
]}
|
||||
]))
|
||||
record_processor_inst.update()
|
||||
|
||||
marks = list([r for r in runtime_storage_inst.get_all_records()
|
||||
if r['record_type'] == 'mark'])
|
||||
|
||||
homer_mark = next(itertools.ifilter(
|
||||
lambda x: x['date'] == (timestamp - 1), marks), None)
|
||||
self.assertTrue(homer_mark['x']) # disagreement
|
||||
self.assertTrue(homer_mark.get('x'),
|
||||
msg='Disagreement: core set -2 after +2')
|
||||
|
||||
homer_mark = next(itertools.ifilter(
|
||||
lambda x: x['date'] == (timestamp + 2), marks), None)
|
||||
self.assertFalse(homer_mark.get('x'),
|
||||
msg='No disagreement: core set +2 after +1')
|
||||
|
||||
bart_mark = next(itertools.ifilter(
|
||||
lambda x: x['date'] == (timestamp + 3), marks), None)
|
||||
self.assertTrue(bart_mark.get('x'),
|
||||
msg='Disagreement: core set +2 after -1')
|
||||
|
||||
def test_commit_merge_date(self):
|
||||
record_processor_inst = self.make_record_processor()
|
||||
@@ -1260,7 +1303,7 @@ def generate_emails(author_name='John Doe', author_email='johndoe@gmail.com',
|
||||
def make_runtime_storage(users=None, companies=None, releases=None,
|
||||
repos=None):
|
||||
runtime_storage_cache = {}
|
||||
runtime_storage_record_keys = set([])
|
||||
runtime_storage_record_keys = []
|
||||
|
||||
def get_by_key(key):
|
||||
if key == 'companies':
|
||||
@@ -1297,7 +1340,7 @@ def make_runtime_storage(users=None, companies=None, releases=None,
|
||||
def set_records(records_iterator):
|
||||
for record in records_iterator:
|
||||
runtime_storage_cache[record['primary_key']] = record
|
||||
runtime_storage_record_keys.add(record['primary_key'])
|
||||
runtime_storage_record_keys.append(record['primary_key'])
|
||||
|
||||
def get_all_records():
|
||||
return [runtime_storage_cache[key]
|
||||
|
||||
Reference in New Issue
Block a user