Skip to content

Commit

Permalink
[api] allow multiple parallel updateinfo counters per incident
Browse files Browse the repository at this point in the history
They depend on the scheme to support different code streams from one incident.

Furthermore only the counter of the default scheme was used before
  • Loading branch information
adrianschroeter committed Jun 26, 2015
1 parent 31d059f commit 474a24f
Show file tree
Hide file tree
Showing 6 changed files with 118 additions and 73 deletions.
19 changes: 19 additions & 0 deletions src/api/app/models/incident_updateinfo_counter_value.rb
@@ -0,0 +1,19 @@
class IncidentUpdateinfoCounterValue < ActiveRecord::Base

belongs_to :updateinfo_counter
belongs_to :project

def self.find_or_create(time, updateinfo_counter, project)

icv = IncidentUpdateinfoCounterValue.where(updateinfo_counter:updateinfo_counter, project: project).first
return icv if icv

# not yet released, get an uniq counter value for this incident and scheme
IncidentUpdateinfoCounterValue.create(released_at: time,
updateinfo_counter:updateinfo_counter,
project: project,
value: updateinfo_counter.increase)
end

end

79 changes: 10 additions & 69 deletions src/api/app/models/maintenance_incident.rb
Expand Up @@ -25,86 +25,27 @@ def project_name
name
end

def initUpdateinfoId(template = "%Y-%C", patch_name = nil)
return if self.released_at
def getUpdateinfoCounter(time, template = "%Y-%C", patch_name = nil)


# set current time, to be used
self.released_at = Time.now.utc
self.name = patch_name

counterType = ""
values = []

# Run an atomar counter++ based on the used scheme
if template =~ /%Y/
counterType << " AND year = ? "
values << self.released_at.year
year = self.released_at.year
else
counterType = " AND ISNULL(year) "
year = nil
end
if template =~ /%M/
counterType << " AND month = ? "
values << self.released_at.month
month = self.released_at.month
else
counterType << " AND ISNULL(month) "
month = nil
end

if template =~ /%D/
counterType << " AND day = ? "
values << self.released_at.day
day = self.released_at.day
else
counterType << " AND ISNULL(day) "
day = nil
end
# FIXME: temporary disabled for validation, clean up including db migration later
# if template =~ /%N/
# name = (self.name||"")
# counterType << " AND name = ? "
# values << name
# else
counterType << " AND ISNULL(name) "
name = nil
# end

r = MaintenanceIncident.exec_query(["SELECT counter FROM updateinfo_counter WHERE maintenance_db_project_id = ? #{counterType} FOR UPDATE",
self.maintenance_db_project_id,*values]).first

unless r
# no counter exists, initialize it and select again
r = MaintenanceIncident.exec_query ["INSERT INTO updateinfo_counter(maintenance_db_project_id, year, month, day, name) VALUES(?,?,?,?,?)",
self.maintenance_db_project_id,year,month,day,name]

r = MaintenanceIncident.exec_query(["SELECT counter FROM updateinfo_counter WHERE maintenance_db_project_id = ? #{counterType} FOR UPDATE",
self.maintenance_db_project_id, *values]).first
end
# do an atomic increase of counter
MaintenanceIncident.exec_query ["UPDATE updateinfo_counter SET counter = counter+1 WHERE maintenance_db_project_id = ? #{counterType}",
self.maintenance_db_project_id,*values]
self.counter = r[0].to_i + 1
self.save!
uc = UpdateinfoCounter.find_or_create(time, self.maintenance_db_project, template)
IncidentUpdateinfoCounterValue.find_or_create(time, uc, self.project)
end

def getUpdateinfoId( id_template, patch_name=nil )
def getUpdateinfoId( id_template, patch_name )
# this is not used anymore, but we need to keep it for released incidents base on old (OBS 2.5) code
return self.updateinfo_id if self.updateinfo_id

# initialize on first run
initUpdateinfoId(id_template, patch_name)
counter = getUpdateinfoCounter(Time.now.utc, id_template, patch_name)

my_id = id_template

# replace place holders
my_id.gsub!( /%C/, self.counter.to_s )
my_id.gsub!( /%Y/, self.released_at.year.to_s )
my_id.gsub!( /%M/, self.released_at.month.to_s )
my_id.gsub!( /%D/, self.released_at.day.to_s )
my_id.gsub!( /%N/, self.name || "" )
my_id.gsub!( /%C/, counter.value.to_s )
my_id.gsub!( /%Y/, counter.released_at.year.to_s )
my_id.gsub!( /%M/, counter.released_at.month.to_s )
my_id.gsub!( /%D/, counter.released_at.day.to_s )
my_id.gsub!( /%N/, patch_name||"" )
my_id.gsub!( /%i/, self.incident_id.to_s )
my_id.gsub!( /%g/, self.id.to_s )

Expand Down
4 changes: 4 additions & 0 deletions src/api/app/models/project.rb
Expand Up @@ -62,6 +62,10 @@ class ForbiddenError < APIException
has_many :maintained_projects, :class_name => 'MaintainedProject', foreign_key: :maintenance_project_id, :dependent => :delete_all
has_many :maintenance_projects, :class_name => 'MaintainedProject', foreign_key: :project_id, :dependent => :delete_all

has_many :incident_updateinfo_counter_values, foreign_key: :project_id, :dependent => :delete_all
has_many :maintenance_incidents, foreign_key: :project_id, :dependent => :delete_all
has_many :maintenance_incidents, foreign_key: :maintenance_db_project_id, :dependent => :delete_all

# develproject is history, use develpackage instead. FIXME3.0: clean this up
has_many :develprojects, :class_name => 'Project', :foreign_key => 'develproject_id'
belongs_to :develproject, :class_name => 'Project'
Expand Down
29 changes: 29 additions & 0 deletions src/api/app/models/updateinfo_counter.rb
@@ -0,0 +1,29 @@
class UpdateinfoCounter < ActiveRecord::Base

def self.find_or_create(time, maintenance_project, template)
year = month = day = nil

year = time.year if template =~ /%Y/
month = time.month if template =~ /%M/
day = time.day if template =~ /%D/

r = UpdateinfoCounter.where(year: year, month: month, day: day).first
r = UpdateinfoCounter.create(year: year, month: month, day: day) unless r

r
end

def increase
# do an atomic increase of counter
counter = nil
self.transaction do
self.lock!
self.increment!(:counter)
counter = self.counter
self.save!
end
return counter
end

end

41 changes: 41 additions & 0 deletions src/api/db/migrate/20150625105426_multiple_incident_counters.rb
@@ -0,0 +1,41 @@

class TempMI < ActiveRecord::Base
self.table_name = 'maintenance_incidents'
end

class MultipleIncidentCounters < ActiveRecord::Migration
def self.up
create_table :incident_updateinfo_counter_values do |t|
t.references :updateinfo_counter, null: false
t.references :project, null: false
t.integer :value, null: false
t.datetime :released_at, null: false
end
add_index :incident_updateinfo_counter_values, [:updateinfo_counter_id, :project_id], :name => "uniq_id_index"
execute("alter table incident_updateinfo_counter_values add foreign key (project_id) references projects(id)")

rename_table :updateinfo_counter, :updateinfo_counters

TempMI.all.each do |mi|
value = mi.counter
next unless value

mp = mi.maintenance_db_project

# there could have been just one so far
uc = UpdateinfoCounter.find_by_maintenance_db_project( mp ).first

IncidentUpdateinfoCounterValue.create(updateinfo_counter: uc, project: mp, value: value)
end

remove_column :maintenance_incidents, :counter
remove_column :maintenance_incidents, :name
end

def self.down
drop_table :incident_updateinfo_counter_values
add_column :maintenance_incidents, :counter, :integer
add_column :maintenance_incidents, :name, :string
rename_table :updateinfo_counters, :updateinfo_counter
end
end
19 changes: 15 additions & 4 deletions src/api/db/structure.sql
Expand Up @@ -585,6 +585,18 @@ CREATE TABLE `incident_counter` (
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `incident_updateinfo_counter_values` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`updateinfo_counter_id` int(11) NOT NULL,
`project_id` int(11) NOT NULL,
`value` int(11) NOT NULL,
`released_at` datetime NOT NULL,
PRIMARY KEY (`id`),
KEY `uniq_id_index` (`updateinfo_counter_id`,`project_id`),
KEY `project_id` (`project_id`),
CONSTRAINT `incident_updateinfo_counter_values_ibfk_1` FOREIGN KEY (`project_id`) REFERENCES `projects` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

CREATE TABLE `issue_trackers` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) CHARACTER SET utf8 NOT NULL,
Expand Down Expand Up @@ -646,9 +658,7 @@ CREATE TABLE `maintenance_incidents` (
`request` int(11) DEFAULT NULL,
`updateinfo_id` varchar(255) CHARACTER SET utf8 DEFAULT NULL,
`incident_id` int(11) DEFAULT NULL,
`counter` int(11) DEFAULT NULL,
`released_at` datetime DEFAULT NULL,
`name` varchar(255) COLLATE utf8_bin DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `index_maintenance_incidents_on_db_project_id` (`db_project_id`),
KEY `index_maintenance_incidents_on_maintenance_db_project_id` (`maintenance_db_project_id`)
Expand Down Expand Up @@ -1040,14 +1050,13 @@ CREATE TABLE `tokens` (
CONSTRAINT `tokens_ibfk_2` FOREIGN KEY (`package_id`) REFERENCES `packages` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

CREATE TABLE `updateinfo_counter` (
CREATE TABLE `updateinfo_counters` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`maintenance_db_project_id` int(11) DEFAULT NULL,
`day` int(11) DEFAULT NULL,
`month` int(11) DEFAULT NULL,
`year` int(11) DEFAULT NULL,
`counter` int(11) DEFAULT '0',
`name` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

Expand Down Expand Up @@ -1638,6 +1647,8 @@ INSERT INTO schema_migrations (version) VALUES ('20150227063641');

INSERT INTO schema_migrations (version) VALUES ('20150623063641');

INSERT INTO schema_migrations (version) VALUES ('20150625105426');

INSERT INTO schema_migrations (version) VALUES ('21');

INSERT INTO schema_migrations (version) VALUES ('22');
Expand Down

0 comments on commit 474a24f

Please sign in to comment.