Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJamie Schembri <jamie@schembri.me>2018-08-01 12:03:14 +0300
committerSean McGivern <sean@mcgivern.me.uk>2018-08-01 12:03:14 +0300
commite72388246b0ab9badfd96cc5888b8d4807daeb89 (patch)
tree8c12a210e89ee6060b3aaa4a351f5d18ed95afaa /app/models/internal_id.rb
parent7586693e0b3e7f0e0bacdd8da082f901031e1c98 (diff)
Resolve "Allow issue's Internal ID (`iid`) to be set when creating via the API"
Diffstat (limited to 'app/models/internal_id.rb')
-rw-r--r--app/models/internal_id.rb36
1 files changed, 35 insertions, 1 deletions
diff --git a/app/models/internal_id.rb b/app/models/internal_id.rb
index f50f28deffe..e5d0f94073c 100644
--- a/app/models/internal_id.rb
+++ b/app/models/internal_id.rb
@@ -1,6 +1,9 @@
# An InternalId is a strictly monotone sequence of integers
# generated for a given scope and usage.
#
+# The monotone sequence may be broken if an ID is explicitly provided
+# to `.track_greatest_and_save!` or `#track_greatest`.
+#
# For example, issues use their project to scope internal ids:
# In that sense, scope is "project" and usage is "issues".
# Generated internal ids for an issue are unique per project.
@@ -25,13 +28,34 @@ class InternalId < ActiveRecord::Base
# The operation locks the record and gathers a `ROW SHARE` lock (in PostgreSQL).
# As such, the increment is atomic and safe to be called concurrently.
def increment_and_save!
+ update_and_save { self.last_value = (last_value || 0) + 1 }
+ end
+
+ # Increments #last_value with new_value if it is greater than the current,
+ # and saves the record
+ #
+ # The operation locks the record and gathers a `ROW SHARE` lock (in PostgreSQL).
+ # As such, the increment is atomic and safe to be called concurrently.
+ def track_greatest_and_save!(new_value)
+ update_and_save { self.last_value = [last_value || 0, new_value].max }
+ end
+
+ private
+
+ def update_and_save(&block)
lock!
- self.last_value = (last_value || 0) + 1
+ yield
save!
last_value
end
class << self
+ def track_greatest(subject, scope, usage, new_value, init)
+ return new_value unless available?
+
+ InternalIdGenerator.new(subject, scope, usage, init).track_greatest(new_value)
+ end
+
def generate_next(subject, scope, usage, init)
# Shortcut if `internal_ids` table is not available (yet)
# This can be the case in other (unrelated) migration specs
@@ -94,6 +118,16 @@ class InternalId < ActiveRecord::Base
end
end
+ # Create a record in internal_ids if one does not yet exist
+ # and set its new_value if it is higher than the current last_value
+ #
+ # Note this will acquire a ROW SHARE lock on the InternalId record
+ def track_greatest(new_value)
+ subject.transaction do
+ (lookup || create_record).track_greatest_and_save!(new_value)
+ end
+ end
+
private
# Retrieve InternalId record for (project, usage) combination, if it exists