Skip to content

Commit

Permalink
[api] improve speed on issue tracking
Browse files Browse the repository at this point in the history
  • Loading branch information
adrianschroeter committed Jan 27, 2015
1 parent 298e26d commit 7b47dc9
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 41 deletions.
93 changes: 52 additions & 41 deletions src/api/app/models/package.rb
Original file line number Diff line number Diff line change
Expand Up @@ -404,12 +404,13 @@ def is_of_kind? kind
end

def update_issue_list
current_issues = []
current_issues = {}
if self.is_patchinfo?
xml = Patchinfo.new.read_patchinfo_xmlhash(self)
xml.elements('issue') do |i|
begin
current_issues << [ Issue.find_or_create_by_name_and_tracker(i['id'], i['tracker']) ,'kept' ]
current_issues['kept'] ||= []
current_issues['kept'] << Issue.find_or_create_by_name_and_tracker(i['id'], i['tracker'])
rescue IssueTracker::NotFoundError => e
# if the issue is invalid, we ignore it
Rails.logger.debug e
Expand All @@ -420,60 +421,70 @@ def update_issue_list
current_issues = find_changed_issues
end

# hash existing entries
pis = Hash.new
self.package_issues.each { |pi| pis[pi.issue.label] = pi }

# new/update issue entries
current_issues.each do |issue, change|
if pi = pis[issue.label]
# issue exists already for this package
unless pi.change == change
# update state
pi.change = change
pi.save!
end
# entry exists already in correct way, do not drop it
pis.delete(issue.label)
else
# new entry
self.package_issues.create(issue: issue, change: change)
end
end

# drop old entries
self.package_issues.delete(pis.values)
# fast sync our relations
PackageIssue.sync_relations(self, current_issues)
end

def parse_issues_xml(query)
def parse_issues_xml(query, force_state=nil)
begin
issues = Suse::Backend.post(self.source_path(nil, query), nil)
xml = Xmlhash.parse(issues.body)
xml.get('issues').elements('issue') do |i|
issue = Issue.find_or_create_by_name_and_tracker(i['name'], i['tracker'])
yield issue, i['state']
end
answer = Suse::Backend.post(self.source_path(nil, query), nil)
rescue ActiveXML::Transport::Error => e
Rails.logger.debug "failed to parse issues: #{e.inspect}"
return {}
end
xml = Xmlhash.parse(answer.body)

# collect all issues and put them into an hash
issues = {}
xml.get('issues').elements('issue') do |i|
issues[i['tracker']] ||= {}
issues[i['tracker']][i['name']] = force_state || i['state']
end

issues
end

def find_changed_issues
issue_change={}
# no expand=1, so only branches are tracked
query = { cmd: :diff, orev: 0, onlyissues: 1, linkrev: :base, view: :xml }
parse_issues_xml(query) do |issue, state|
issue_change[issue] = 'kept'
issue_change = parse_issues_xml(query, 'kept')
# issues introduced by local changes
if self.is_link?
query = { cmd: :linkdiff, onlyissues: 1, linkrev: :base, view: :xml }
new = parse_issues_xml(query)
(issue_change.keys + new.keys).uniq.each do |key|
issue_change[key] ||= {}
issue_change[key].merge!(new[key]) if new[key]
issue_change['kept'].delete(new[key]) if issue_change['kept'] and key != 'kept'
end
end

# issues introduced by local changes
return issue_change unless self.is_link?
query = { cmd: :linkdiff, onlyissues: 1, linkrev: :base, view: :xml }
parse_issues_xml(query) do |issue, state|
issue_change[issue] = state
myissues = {}
Issue.transaction do
# update existing issues
self.issues.each do |issue|
next unless issue_change[issue.issue_tracker.name]
next unless issue_change[issue.issue_tracker.name][issue.name]
state = issue_change[issue.issue_tracker.name][issue.name]
myissues[state] ||= []
myissues[state] << issue
issue_change[issue.issue_tracker.name].delete(issue.name)
end

issue_change.keys.each do |tracker|
t=IssueTracker.find_by_name tracker

# create new issues
issue_change[tracker].keys.each do |name|
issue = t.issues.find_by_name(name) || t.issues.create(name: name)
state = issue_change[tracker][name]
myissues[state] ||= []
myissues[state] << issue
end
end
end

issue_change
myissues
end

def update_channel_list
Expand Down
21 changes: 21 additions & 0 deletions src/api/app/models/package_issue.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,25 @@
class PackageIssue < ActiveRecord::Base
belongs_to :package
belongs_to :issue

def self.sync_relations(package, issues)
PackageIssue.transaction do
allissues=[]
issues.map{|h| allissues += h.last}

# drop not anymore existing relations
PackageIssue.where("package_id = ? AND NOT issue_id IN (?)", package, allissues).delete_all

# create missing in an efficient way
sql=ActiveRecord::Base.connection()
(allissues - package.issues.to_ary).each do |i|
sql.execute("INSERT INTO `package_issues` (`package_id`, `issue_id`) VALUES (#{package.id},#{i.id})")
end

# set change value for all
issues.each do |pair|
PackageIssue.where(package: package, issue: pair.last).update_all(change: pair.first)
end
end
end
end
4 changes: 4 additions & 0 deletions src/api/test/functional/maintenance_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -750,6 +750,10 @@ def test_create_maintenance_project_and_release_packages
post '/source/'+incidentProject+'/pack2.BaseDistro2.0_LinkedUpdateProject?unified=1&cmd=diff&filelimit=0&expand=1'
assert_response :success
assert_match(/DUMMY bnc#1042/, @response.body)
get "/source/#{incidentProject}/pack2.BaseDistro2.0_LinkedUpdateProject?view=issues"
assert_response :success
assert_xml_tag :parent => { tag: 'issue', :attributes=>{change:"added"} },
:tag=>'name', :content=>'1042'

# add a new package with defined link target
Timecop.freeze(1)
Expand Down
1 change: 1 addition & 0 deletions src/api/test/unit/code_quality_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ def setup
'MaintenanceHelper#instantiate_container' => 129.98,
'Owner::_extract_from_container' => 84.07,
'PersonController#internal_register' => 112.01,
'Package#find_changed_issues' => 93.74,
'Project#update_one_repository_without_path' => 150.7,
'PublicController#binary_packages' => 126.16,
'Repository#cleanup_before_destroy' => 82.98,
Expand Down

0 comments on commit 7b47dc9

Please sign in to comment.