[ARVADOS] created: 1.1.4-263-g764334d

Git user git at public.curoverse.com
Mon May 14 11:33:05 EDT 2018


        at  764334dee966e04161d411a9feb0074b99faa147 (commit)


commit 764334dee966e04161d411a9feb0074b99faa147
Author: Tom Clegg <tclegg at veritasgenetics.com>
Date:   Mon May 14 10:28:36 2018 -0400

    13164: Lock tables when updating multiple containers + CRs.
    
    Avoid database inconsistencies after update races.
    
    Arvados-DCO-1.1-Signed-off-by: Tom Clegg <tclegg at veritasgenetics.com>

diff --git a/services/api/app/models/container.rb b/services/api/app/models/container.rb
index 8882b2c..e9d4f83 100644
--- a/services/api/app/models/container.rb
+++ b/services/api/app/models/container.rb
@@ -126,6 +126,7 @@ class Container < ArvadosModel
       # Update the priority of child container requests to match new
       # priority of the parent container (ignoring requests with no
       # container assigned, because their priority doesn't matter).
+      ActiveRecord::Base.connection.execute('LOCK container_requests, containers IN EXCLUSIVE MODE')
       ContainerRequest.
         where(requesting_container_uuid: self.uuid,
               state: ContainerRequest::Committed).
@@ -541,6 +542,7 @@ class Container < ArvadosModel
     if self.state_changed? and self.final?
       act_as_system_user do
 
+        ActiveRecord::Base.connection.execute('LOCK container_requests, containers IN EXCLUSIVE MODE')
         if self.state == Cancelled
           retryable_requests = ContainerRequest.where("container_uuid = ? and priority > 0 and state = 'Committed' and container_count < container_count_max", uuid)
         else
diff --git a/services/api/app/models/container_request.rb b/services/api/app/models/container_request.rb
index bc01b33..ac4415b 100644
--- a/services/api/app/models/container_request.rb
+++ b/services/api/app/models/container_request.rb
@@ -37,10 +37,10 @@ class ContainerRequest < ArvadosModel
   validate :check_update_whitelist
   validate :secret_mounts_key_conflict
   before_save :scrub_secret_mounts
-  after_save :update_priority
-  after_save :finalize_if_needed
   before_create :set_requesting_container_uuid
   before_destroy :set_priority_zero
+  after_save :update_priority
+  after_save :finalize_if_needed
 
   api_accessible :user, extend: :common do |t|
     t.add :command
@@ -86,7 +86,7 @@ class ContainerRequest < ArvadosModel
   AttrsPermittedAlways = [:owner_uuid, :state, :name, :description]
   AttrsPermittedBeforeCommit = [:command, :container_count_max,
   :container_image, :cwd, :environment, :filters, :mounts,
-  :output_path, :priority, :properties, :requesting_container_uuid,
+  :output_path, :priority, :properties,
   :runtime_constraints, :state, :container_uuid, :use_existing,
   :scheduling_parameters, :secret_mounts, :output_name, :output_ttl]
 
@@ -286,9 +286,9 @@ class ContainerRequest < ArvadosModel
   def update_priority
     return unless state_changed? || priority_changed? || container_uuid_changed?
     act_as_system_user do
+      ActiveRecord::Base.connection.execute('LOCK container_requests, containers IN EXCLUSIVE MODE')
       Container.
         where('uuid in (?)', [self.container_uuid_was, self.container_uuid].compact).
-        lock(true).
         map(&:update_priority!)
     end
   end
@@ -298,14 +298,11 @@ class ContainerRequest < ArvadosModel
   end
 
   def set_requesting_container_uuid
-    return !new_record? if self.requesting_container_uuid   # already set
-
-    token_uuid = current_api_client_authorization.andand.uuid
-    container = Container.where('auth_uuid=?', token_uuid).order('created_at desc').first
-    if container
-      self.requesting_container_uuid = container.uuid
-      self.priority = container.priority > 0 ? 1 : 0
+    return if !current_api_client_authorization
+    ActiveRecord::Base.connection.execute('LOCK container_requests, containers IN EXCLUSIVE MODE')
+    if (c = Container.where('auth_uuid=?', current_api_client_authorization.uuid).select([:uuid, :priority]).first)
+      self.requesting_container_uuid = c.uuid
+      self.priority = c.priority>0 ? 1 : 0
     end
-    true
   end
 end
diff --git a/services/api/db/migrate/20180514135529_add_container_auth_uuid_index.rb b/services/api/db/migrate/20180514135529_add_container_auth_uuid_index.rb
new file mode 100644
index 0000000..56cafea
--- /dev/null
+++ b/services/api/db/migrate/20180514135529_add_container_auth_uuid_index.rb
@@ -0,0 +1,5 @@
+class AddContainerAuthUuidIndex < ActiveRecord::Migration
+  def change
+    add_index :containers, :auth_uuid
+  end
+end
diff --git a/services/api/db/structure.sql b/services/api/db/structure.sql
index caf7683..0ab30c5 100644
--- a/services/api/db/structure.sql
+++ b/services/api/db/structure.sql
@@ -1879,6 +1879,13 @@ CREATE UNIQUE INDEX index_container_requests_on_uuid ON container_requests USING
 
 
 --
+-- Name: index_containers_on_auth_uuid; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE INDEX index_containers_on_auth_uuid ON containers USING btree (auth_uuid);
+
+
+--
 -- Name: index_containers_on_modified_at_uuid; Type: INDEX; Schema: public; Owner: -
 --
 
@@ -3071,3 +3078,5 @@ INSERT INTO schema_migrations (version) VALUES ('20180313180114');
 
 INSERT INTO schema_migrations (version) VALUES ('20180501182859');
 
+INSERT INTO schema_migrations (version) VALUES ('20180514135529');
+
diff --git a/services/api/test/unit/container_request_test.rb b/services/api/test/unit/container_request_test.rb
index cc257cc..3483b87 100644
--- a/services/api/test/unit/container_request_test.rb
+++ b/services/api/test/unit/container_request_test.rb
@@ -261,10 +261,12 @@ class ContainerRequestTest < ActiveSupport::TestCase
 
     c = Container.find_by_uuid cr.container_uuid
     assert_operator 0, :<, c.priority
+    lock_and_run(c)
 
-    cr2 = create_minimal_req!
-    cr2.update_attributes!(priority: 10, state: "Committed", requesting_container_uuid: c.uuid, command: ["echo", "foo2"], container_count_max: 1)
-    cr2.reload
+    cr2 = with_container_auth(c) do
+      create_minimal_req!(priority: 10, state: "Committed", container_count_max: 1, command: ["echo", "foo2"])
+    end
+    assert_not_nil cr2.requesting_container_uuid
     assert_equal users(:active).uuid, cr2.modified_by_user_uuid
 
     c2 = Container.find_by_uuid cr2.container_uuid
@@ -613,7 +615,7 @@ class ContainerRequestTest < ActiveSupport::TestCase
 
   test "requesting_container_uuid at create is not allowed" do
     set_user_from_auth :active
-    assert_raises(ActiveRecord::RecordNotSaved) do
+    assert_raises(ActiveRecord::RecordInvalid) do
       create_minimal_req!(state: "Uncommitted", priority: 1, requesting_container_uuid: 'youcantdothat')
     end
   end

-----------------------------------------------------------------------


hooks/post-receive
-- 




More information about the arvados-commits mailing list