[ARVADOS] created: 1.2.0-71-ga18fe6288
Git user
git at public.curoverse.com
Thu Oct 4 15:31:38 EDT 2018
at a18fe628853e2042bb104088dd586cb8f41adcef (commit)
commit a18fe628853e2042bb104088dd586cb8f41adcef
Author: Lucas Di Pentima <ldipentima at veritasgenetics.com>
Date: Thu Oct 4 15:54:18 2018 -0300
13561: Avoid permission links to be attached to past collection versions.
Arvados-DCO-1.1-Signed-off-by: Lucas Di Pentima <ldipentima at veritasgenetics.com>
diff --git a/services/api/app/models/link.rb b/services/api/app/models/link.rb
index dc961667b..bf21cf4b6 100644
--- a/services/api/app/models/link.rb
+++ b/services/api/app/models/link.rb
@@ -48,8 +48,12 @@ class Link < ArvadosModel
# Administrators can grant permissions
return true if current_user.is_admin
- # All users can grant permissions on objects they own or can manage
head_obj = ArvadosModel.find_by_uuid(head_uuid)
+
+ # No permission links can be pointed to past collection versions
+ return false if head_obj.is_a?(Collection) && head_obj.current_version_uuid != head_uuid
+
+ # All users can grant permissions on objects they own or can manage
return true if current_user.can?(manage: head_obj)
# Default = deny.
diff --git a/services/api/test/fixtures/collections.yml b/services/api/test/fixtures/collections.yml
index 2bc362a4c..62bb644c0 100644
--- a/services/api/test/fixtures/collections.yml
+++ b/services/api/test/fixtures/collections.yml
@@ -94,6 +94,21 @@ w_a_z_file:
updated_at: 2015-02-09T10:53:38Z
manifest_text: ". 4c6c2c0ac8aa0696edd7316a3be5ca3c+5 0:5:w\\040\\141\\040z\n"
name: "\"w a z\" file"
+ version: 2
+
+w_a_z_file_version_1:
+ uuid: zzzzz-4zz18-25k12570yk1ver1
+ current_version_uuid: zzzzz-4zz18-25k12570yk134b3
+ portable_data_hash: 8706aadd12a0ebc07d74cae88762ba9e+56
+ owner_uuid: zzzzz-tpzed-xurymjxw79nv3jz
+ created_at: 2015-02-09T10:53:38Z
+ modified_by_client_uuid: zzzzz-ozdt8-brczlopd8u8d0jr
+ modified_by_user_uuid: zzzzz-tpzed-d9tiejq69daie8f
+ modified_at: 2015-02-09T10:53:38Z
+ updated_at: 2015-02-09T10:53:38Z
+ manifest_text: ". 4c6c2c0ac8aa0696edd7316a3be5ca3c+5 0:5:w\\040\\141\\040z\n"
+ name: "waz file"
+ version: 1
multilevel_collection_1:
uuid: zzzzz-4zz18-pyw8yp9g3pr7irn
diff --git a/services/api/test/unit/link_test.rb b/services/api/test/unit/link_test.rb
index cba5d20cb..00f3cc291 100644
--- a/services/api/test/unit/link_test.rb
+++ b/services/api/test/unit/link_test.rb
@@ -80,4 +80,9 @@ class LinkTest < ActiveSupport::TestCase
test "link granting project permissions to unreadable user is invalid" do
refute new_active_link_valid?(tail_uuid: users(:admin).uuid)
end
+
+ test "permission link can't exist on past collection versions" do
+ refute new_active_link_valid?(tail_uuid: groups(:public).uuid,
+ head_uuid: collections(:w_a_z_file_version_1).uuid)
+ end
end
commit 762e0ab6ac28f783c5d0c9fdec438f13418f9ad6
Author: Lucas Di Pentima <ldipentima at veritasgenetics.com>
Date: Thu Oct 4 15:22:31 2018 -0300
13561: Expand index API to include past versions.
Arvados-DCO-1.1-Signed-off-by: Lucas Di Pentima <ldipentima at veritasgenetics.com>
diff --git a/services/api/app/controllers/application_controller.rb b/services/api/app/controllers/application_controller.rb
index 05b39c1ae..a6718dd4d 100644
--- a/services/api/app/controllers/application_controller.rb
+++ b/services/api/app/controllers/application_controller.rb
@@ -189,7 +189,10 @@ class ApplicationController < ActionController::Base
end
def find_objects_for_index
- @objects ||= model_class.readable_by(*@read_users, {:include_trash => (params[:include_trash] || 'untrash' == action_name)})
+ @objects ||= model_class.readable_by(*@read_users, {
+ :include_trash => (params[:include_trash] || 'untrash' == action_name),
+ :include_old_versions => params[:include_old_versions]
+ })
apply_where_limit_order_params
end
diff --git a/services/api/app/controllers/arvados/v1/collections_controller.rb b/services/api/app/controllers/arvados/v1/collections_controller.rb
index 6e77c12a1..cfd1e9dc2 100644
--- a/services/api/app/controllers/arvados/v1/collections_controller.rb
+++ b/services/api/app/controllers/arvados/v1/collections_controller.rb
@@ -27,9 +27,14 @@ class Arvados::V1::CollectionsController < ApplicationController
end
def find_objects_for_index
+ opts = {}
if params[:include_trash] || ['destroy', 'trash', 'untrash'].include?(action_name)
- @objects = Collection.readable_by(*@read_users, {include_trash: true})
+ opts.update({include_trash: true})
end
+ if params[:include_old_versions]
+ opts.update({include_old_versions: true})
+ end
+ @objects = Collection.readable_by(*@read_users, opts) if !opts.empty?
super
end
@@ -223,4 +228,17 @@ class Arvados::V1::CollectionsController < ApplicationController
@select ||= model_class.selectable_attributes - ["manifest_text", "unsigned_manifest_text"]
end
end
+
+ def load_filters_param
+ super
+ return if !params[:include_old_versions]
+ @filters = @filters.map do |col, operator, operand|
+ # Replace uuid filters when including past versions
+ if col == 'uuid'
+ ['current_version_uuid', operator, operand]
+ else
+ [col, operator, operand]
+ end
+ end
+ end
end
diff --git a/services/api/app/models/arvados_model.rb b/services/api/app/models/arvados_model.rb
index c983372ad..801da17db 100644
--- a/services/api/app/models/arvados_model.rb
+++ b/services/api/app/models/arvados_model.rb
@@ -369,7 +369,13 @@ class ArvadosModel < ActiveRecord::Base
end
self[:name] = new_name
- self[:uuid] = nil if uuid_was.nil? && !uuid.nil?
+ if uuid_was.nil? && !uuid.nil?
+ self[:uuid] = nil
+ if self.is_a? Collection
+ # Reset so that is assigned to the new UUID
+ self[:current_version_uuid] = nil
+ end
+ end
conn.exec_query 'SAVEPOINT save_with_unique_name'
retry
ensure
diff --git a/services/api/app/models/collection.rb b/services/api/app/models/collection.rb
index 349c002ef..2e79d7460 100644
--- a/services/api/app/models/collection.rb
+++ b/services/api/app/models/collection.rb
@@ -29,7 +29,6 @@ class Collection < ArvadosModel
validate :ensure_storage_classes_contain_non_empty_strings
validate :old_versions_cannot_be_updated, on: :update
before_save :set_file_names
- before_create :set_current_version_uuid
api_accessible :user, extend: :common do |t|
t.add :name
@@ -219,10 +218,6 @@ class Collection < ArvadosModel
['current_version_uuid']
end
- def set_current_version_uuid
- self.current_version_uuid ||= self.uuid
- end
-
def save! *args
# Skip if feature is disabled or saving a new record
if !Rails.configuration.collection_versioning || new_record?
@@ -547,7 +542,7 @@ class Collection < ArvadosModel
end
def self.searchable_columns operator
- super - ["manifest_text", "current_version_uuid"]
+ super - ["manifest_text"]
end
def self.full_text_searchable_columns
@@ -632,4 +627,10 @@ class Collection < ArvadosModel
raise ArvadosModel::PermissionDeniedError.new("previous versions cannot be updated")
end
end
+
+ def assign_uuid
+ super
+ self.current_version_uuid ||= self.uuid
+ true
+ end
end
diff --git a/services/api/db/migrate/20181004131141_add_current_version_uuid_to_collection_search_index.rb b/services/api/db/migrate/20181004131141_add_current_version_uuid_to_collection_search_index.rb
new file mode 100644
index 000000000..63e99191a
--- /dev/null
+++ b/services/api/db/migrate/20181004131141_add_current_version_uuid_to_collection_search_index.rb
@@ -0,0 +1,17 @@
+# Copyright (C) The Arvados Authors. All rights reserved.
+#
+# SPDX-License-Identifier: AGPL-3.0
+
+class AddCurrentVersionUuidToCollectionSearchIndex < ActiveRecord::Migration
+ disable_ddl_transaction!
+
+ def up
+ remove_index :collections, :name => 'collections_search_index'
+ add_index :collections, ["owner_uuid", "modified_by_client_uuid", "modified_by_user_uuid", "portable_data_hash", "uuid", "name", "current_version_uuid"], name: 'collections_search_index', algorithm: :concurrently
+ end
+
+ def down
+ remove_index :collections, :name => 'collections_search_index'
+ add_index :collections, ["owner_uuid", "modified_by_client_uuid", "modified_by_user_uuid", "portable_data_hash", "uuid", "name"], name: 'collections_search_index', algorithm: :concurrently
+ end
+end
diff --git a/services/api/db/structure.sql b/services/api/db/structure.sql
index 67bc6856d..71d630f6e 100644
--- a/services/api/db/structure.sql
+++ b/services/api/db/structure.sql
@@ -1634,7 +1634,7 @@ CREATE INDEX collections_full_text_search_idx ON public.collections USING gin (t
-- Name: collections_search_index; Type: INDEX; Schema: public; Owner: -
--
-CREATE INDEX collections_search_index ON public.collections USING btree (owner_uuid, modified_by_client_uuid, modified_by_user_uuid, portable_data_hash, uuid, name);
+CREATE INDEX collections_search_index ON public.collections USING btree (owner_uuid, modified_by_client_uuid, modified_by_user_uuid, portable_data_hash, uuid, name, current_version_uuid);
--
@@ -3187,3 +3187,5 @@ INSERT INTO schema_migrations (version) VALUES ('20180919001158');
INSERT INTO schema_migrations (version) VALUES ('20181001175023');
+INSERT INTO schema_migrations (version) VALUES ('20181004131141');
+
diff --git a/services/api/test/functional/arvados/v1/collections_controller_test.rb b/services/api/test/functional/arvados/v1/collections_controller_test.rb
index 970368479..24a1a09cf 100644
--- a/services/api/test/functional/arvados/v1/collections_controller_test.rb
+++ b/services/api/test/functional/arvados/v1/collections_controller_test.rb
@@ -45,6 +45,17 @@ class Arvados::V1::CollectionsControllerTest < ActionController::TestCase
"basic Collections index included past version")
end
+ test "get index with include_old_versions" do
+ authorize_with :active
+ get :index, {
+ include_old_versions: true
+ }
+ assert_response :success
+ assert(assigns(:objects).andand.any?, "no Collections returned in index")
+ assert(json_response["items"].any? { |c| c["uuid"] == collections(:collection_owned_by_active_past_version_1).uuid },
+ "past version not included on index")
+ end
+
test "collections.get returns signed locators, and no unsigned_manifest_text" do
permit_unsigned_manifests
authorize_with :active
@@ -1145,4 +1156,21 @@ EOS
end
assert_includes(item_uuids, collections(:collection_in_trashed_subproject).uuid)
end
+
+ test 'can get collection with past versions' do
+ authorize_with :active
+ get :index, {
+ filters: [['uuid','=',collections(:collection_owned_by_active).uuid]],
+ include_old_versions: true
+ }
+ assert_response :success
+ assert_equal 2, assigns(:objects).length
+ assert_equal 2, json_response['items_available']
+ assert_equal 2, json_response['items'].count
+ json_response['items'].each do |c|
+ assert_equal collections(:collection_owned_by_active).uuid,
+ c['current_version_uuid'],
+ 'response includes a version from a different collection'
+ end
+ end
end
commit 14cfc3a648e17b4e52fd8cc17c9250291e53afa7
Author: Lucas Di Pentima <ldipentima at veritasgenetics.com>
Date: Wed Oct 3 17:11:38 2018 -0300
13561: Avoid collections.index to include old versions
Arvados-DCO-1.1-Signed-off-by: Lucas Di Pentima <ldipentima at veritasgenetics.com>
diff --git a/services/api/app/models/arvados_model.rb b/services/api/app/models/arvados_model.rb
index 4ba4ac771..c983372ad 100644
--- a/services/api/app/models/arvados_model.rb
+++ b/services/api/app/models/arvados_model.rb
@@ -240,7 +240,7 @@ class ArvadosModel < ActiveRecord::Base
end.compact.uniq
end
- # Return a query with read permissions restricted to the union of of the
+ # Return a query with read permissions restricted to the union of the
# permissions of the members of users_list, i.e. if something is readable by
# any user in users_list, it will be readable in the query returned by this
# function.
@@ -258,6 +258,7 @@ class ArvadosModel < ActiveRecord::Base
# Collect the UUIDs of the authorized users.
sql_table = kwargs.fetch(:table_name, table_name)
include_trash = kwargs.fetch(:include_trash, false)
+ include_old_versions = kwargs.fetch(:include_old_versions, false)
sql_conds = nil
user_uuids = users_list.map { |u| u.uuid }
@@ -268,6 +269,11 @@ class ArvadosModel < ActiveRecord::Base
exclude_trashed_records = "AND #{sql_table}.is_trashed = false"
end
+ exclude_old_versions = ""
+ if !include_old_versions && sql_table == "collections"
+ exclude_old_versions = "AND #{sql_table}.uuid = #{sql_table}.current_version_uuid"
+ end
+
if users_list.select { |u| u.is_admin }.any?
# Admin skips most permission checks, but still want to filter on trashed items.
if !include_trash
@@ -275,7 +281,7 @@ class ArvadosModel < ActiveRecord::Base
# Only include records where the owner is not trashed
sql_conds = "NOT EXISTS(SELECT 1 FROM #{PERMISSION_VIEW} "+
"WHERE trashed = 1 AND "+
- "(#{sql_table}.owner_uuid = target_uuid)) #{exclude_trashed_records}"
+ "(#{sql_table}.owner_uuid = target_uuid)) #{exclude_trashed_records} #{exclude_old_versions}"
end
end
else
@@ -312,7 +318,7 @@ class ArvadosModel < ActiveRecord::Base
"(#{sql_table}.head_uuid IN (:user_uuids) OR #{sql_table}.tail_uuid IN (:user_uuids)))"
end
- sql_conds = "(#{direct_check} #{owner_check} #{links_cond}) #{exclude_trashed_records}"
+ sql_conds = "(#{direct_check} #{owner_check} #{links_cond}) #{exclude_trashed_records} #{exclude_old_versions}"
end
diff --git a/services/api/app/models/collection.rb b/services/api/app/models/collection.rb
index a449b5ef6..349c002ef 100644
--- a/services/api/app/models/collection.rb
+++ b/services/api/app/models/collection.rb
@@ -47,6 +47,9 @@ class Collection < ArvadosModel
t.add :delete_at
t.add :trash_at
t.add :is_trashed
+ t.add :version
+ t.add :current_version_uuid
+ t.add :preserve_version
end
after_initialize do
diff --git a/services/api/test/fixtures/collections.yml b/services/api/test/fixtures/collections.yml
index 3578651ba..2bc362a4c 100644
--- a/services/api/test/fixtures/collections.yml
+++ b/services/api/test/fixtures/collections.yml
@@ -27,6 +27,21 @@ collection_owned_by_active:
updated_at: 2014-02-03T17:22:54Z
manifest_text: ". 37b51d194a7513e45b56f6524f2d51f2+3 0:3:bar\n"
name: owned_by_active
+ version: 2
+
+collection_owned_by_active_past_version_1:
+ uuid: zzzzz-4zz18-znfnqtbbv4spast
+ current_version_uuid: zzzzz-4zz18-bv31uwvy3neko21
+ portable_data_hash: fa7aeb5140e2848d39b416daeef4ffc5+45
+ owner_uuid: zzzzz-tpzed-xurymjxw79nv3jz
+ created_at: 2014-02-03T17:22:54Z
+ modified_by_client_uuid: zzzzz-ozdt8-brczlopd8u8d0jr
+ modified_by_user_uuid: zzzzz-tpzed-d9tiejq69daie8f
+ modified_at: 2014-02-03T15:22:54Z
+ updated_at: 2014-02-03T15:22:54Z
+ manifest_text: ". 37b51d194a7513e45b56f6524f2d51f2+3 0:3:bar\n"
+ name: owned_by_active_version_1
+ version: 1
foo_file:
uuid: zzzzz-4zz18-znfnqtbbv4spc3w
diff --git a/services/api/test/functional/arvados/v1/collections_controller_test.rb b/services/api/test/functional/arvados/v1/collections_controller_test.rb
index e6ecea219..970368479 100644
--- a/services/api/test/functional/arvados/v1/collections_controller_test.rb
+++ b/services/api/test/functional/arvados/v1/collections_controller_test.rb
@@ -41,6 +41,8 @@ class Arvados::V1::CollectionsControllerTest < ActionController::TestCase
assert(assigns(:objects).andand.any?, "no Collections returned in index")
refute(json_response["items"].any? { |c| c.has_key?("manifest_text") },
"basic Collections index included manifest_text")
+ refute(json_response["items"].any? { |c| c["uuid"] == collections(:collection_owned_by_active_past_version_1).uuid },
+ "basic Collections index included past version")
end
test "collections.get returns signed locators, and no unsigned_manifest_text" do
commit f0a85e273056d0ad440084c11a37c73ce25fb4f6
Author: Lucas Di Pentima <ldipentima at veritasgenetics.com>
Date: Tue Oct 2 14:51:35 2018 -0300
13561: Save new version when preserve_version==true or config idle time is up.
Arvados-DCO-1.1-Signed-off-by: Lucas Di Pentima <ldipentima at veritasgenetics.com>
diff --git a/services/api/app/models/collection.rb b/services/api/app/models/collection.rb
index 025811cf8..a449b5ef6 100644
--- a/services/api/app/models/collection.rb
+++ b/services/api/app/models/collection.rb
@@ -221,9 +221,19 @@ class Collection < ArvadosModel
end
def save! *args
- if !Rails.configuration.collection_versioning || new_record? || (!self.changes.include?('uuid') && current_version_uuid != uuid)
+ # Skip if feature is disabled or saving a new record
+ if !Rails.configuration.collection_versioning || new_record?
return super
end
+ # Skip if updating a past version
+ if !self.changes.include?('uuid') && current_version_uuid != uuid
+ return super
+ end
+ # Skip if current version shouldn't (explicitly or implicitly) be preserved
+ if !should_preserve_version?
+ return super
+ end
+
changes = self.changes
# Updates that will be synced with older versions
synced_updates = ['uuid', 'owner_uuid', 'delete_at', 'trash_at', 'is_trashed',
@@ -231,10 +241,18 @@ class Collection < ArvadosModel
# Updates that will produce a new version
versionable_updates = ['manifest_text', 'description', 'properties', 'name'] & changes.keys
- if versionable_updates.empty? && synced_updates.empty?
- # Updates don't include interesting attributes, so don't save a new snapshot nor
- # sync older versions.
- return super
+ if versionable_updates.empty?
+ # Keep preserve_version enabled for the next update, if applicable.
+ self.preserve_version ||= self.preserve_version_was
+ if !self.changes.include?('preserve_version')
+ changes.delete('preserve_version')
+ end
+
+ if synced_updates.empty?
+ # Updates don't include interesting attributes, so don't save a new
+ # snapshot nor sync older versions.
+ return super
+ end
end
# Does row locking (transaction is implicit) because 'version'
@@ -273,6 +291,7 @@ class Collection < ArvadosModel
snapshot.created_at = created_at
# Update current version number
self.version += 1
+ self.preserve_version = false
end
# Restore requested changes on the current version
changes.keys.each do |attr|
@@ -287,6 +306,16 @@ class Collection < ArvadosModel
end
end
+ def should_preserve_version?
+ idle_threshold = Rails.configuration.preserve_version_if_idle
+ if !self.preserve_version_was &&
+ (idle_threshold < 0 ||
+ (idle_threshold > 0 && self.modified_at_was > db_current_time-idle_threshold.seconds))
+ return false
+ end
+ return true
+ end
+
def check_encoding
if manifest_text.encoding.name == 'UTF-8' and manifest_text.valid_encoding?
true
diff --git a/services/api/config/application.default.yml b/services/api/config/application.default.yml
index f480904c4..c9b7ee988 100644
--- a/services/api/config/application.default.yml
+++ b/services/api/config/application.default.yml
@@ -500,9 +500,16 @@ common:
# keep_web_service_url: https://download.uuid_prefix.arvadosapi.com/
keep_web_service_url: false
- # If true, enable collection versioning: With every update, a snapshot of the
- # collection's previous state is created and linked to the current collection.
+ # If true, enable collection versioning.
+ # When a collection's preserve_version field is true or the current version
+ # is older than the amount of seconds defined on preserve_version_if_idle,
+ # a snapshot of the collection's previous state is created and linked to
+ # the current collection.
collection_versioning: false
+ # 0 = auto-create a new version on every update.
+ # -1 = never auto-create new versions.
+ # > 0 = auto-create a new version when older than the specified number of seconds.
+ preserve_version_if_idle: -1
development:
force_ssl: false
diff --git a/services/api/db/migrate/20181001175023_add_preserve_version_to_collections.rb b/services/api/db/migrate/20181001175023_add_preserve_version_to_collections.rb
new file mode 100644
index 000000000..fbdc397fc
--- /dev/null
+++ b/services/api/db/migrate/20181001175023_add_preserve_version_to_collections.rb
@@ -0,0 +1,9 @@
+# Copyright (C) The Arvados Authors. All rights reserved.
+#
+# SPDX-License-Identifier: AGPL-3.0
+
+class AddPreserveVersionToCollections < ActiveRecord::Migration
+ def change
+ add_column :collections, :preserve_version, :boolean, default: false
+ end
+end
diff --git a/services/api/db/structure.sql b/services/api/db/structure.sql
index de5e2e127..67bc6856d 100644
--- a/services/api/db/structure.sql
+++ b/services/api/db/structure.sql
@@ -174,7 +174,8 @@ CREATE TABLE public.collections (
storage_classes_confirmed jsonb DEFAULT '[]'::jsonb,
storage_classes_confirmed_at timestamp without time zone,
current_version_uuid character varying,
- version integer DEFAULT 1 NOT NULL
+ version integer DEFAULT 1 NOT NULL,
+ preserve_version boolean DEFAULT false
);
@@ -3184,3 +3185,5 @@ INSERT INTO schema_migrations (version) VALUES ('20180915155335');
INSERT INTO schema_migrations (version) VALUES ('20180919001158');
+INSERT INTO schema_migrations (version) VALUES ('20181001175023');
+
diff --git a/services/api/test/unit/collection_test.rb b/services/api/test/unit/collection_test.rb
index 569e589b2..a1008eec4 100644
--- a/services/api/test/unit/collection_test.rb
+++ b/services/api/test/unit/collection_test.rb
@@ -106,8 +106,76 @@ class CollectionTest < ActiveSupport::TestCase
end
end
+ test "auto-create version after idle setting" do
+ Rails.configuration.collection_versioning = true
+ Rails.configuration.preserve_version_if_idle = 600 # 10 minutes
+ act_as_user users(:active) do
+ # Set up initial collection
+ c = create_collection 'foo', Encoding::US_ASCII
+ assert c.valid?
+ assert_equal 1, c.version
+ assert_equal false, c.preserve_version
+ # Make a versionable update, it shouldn't create a new version yet
+ c.update_attributes!({'name' => 'bar'})
+ c.reload
+ assert_equal 'bar', c.name
+ assert_equal 1, c.version
+ # Update modified_at to trigger a version auto-creation
+ fifteen_min_ago = Time.now - 15.minutes
+ c.update_column('modified_at', fifteen_min_ago) # Update without validations/callbacks
+ c.reload
+ assert_equal fifteen_min_ago.to_i, c.modified_at.to_i
+ c.update_attributes!({'name' => 'baz'})
+ c.reload
+ assert_equal 'baz', c.name
+ assert_equal 2, c.version
+ # Make another update, no new version should be created
+ c.update_attributes!({'name' => 'foobar'})
+ c.reload
+ assert_equal 'foobar', c.name
+ assert_equal 2, c.version
+ end
+ end
+
+ test "preserve_version=false assignment is ignored while being true and not producing a new version" do
+ Rails.configuration.collection_versioning = true
+ Rails.configuration.preserve_version_if_idle = 3600
+ act_as_user users(:active) do
+ # Set up initial collection
+ c = create_collection 'foo', Encoding::US_ASCII
+ assert c.valid?
+ assert_equal 1, c.version
+ assert_equal false, c.preserve_version
+ # This update shouldn't produce a new version, as the idle time is not up
+ c.update_attributes!({
+ 'name' => 'bar',
+ 'preserve_version' => true
+ })
+ c.reload
+ assert_equal 1, c.version
+ assert_equal 'bar', c.name
+ assert_equal true, c.preserve_version
+ # Make sure preserve_version is not disabled after being enabled, unless
+ # a new version is created.
+ c.update_attributes!({
+ 'preserve_version' => false,
+ 'replication_desired' => 2
+ })
+ c.reload
+ assert_equal 1, c.version
+ assert_equal 2, c.replication_desired
+ assert_equal true, c.preserve_version
+ c.update_attributes!({'name' => 'foobar'})
+ c.reload
+ assert_equal 2, c.version
+ assert_equal false, c.preserve_version
+ assert_equal 'foobar', c.name
+ end
+ end
+
test "uuid updates on current version make older versions update their pointers" do
Rails.configuration.collection_versioning = true
+ Rails.configuration.preserve_version_if_idle = 0
act_as_system_user do
# Set up initial collection
c = create_collection 'foo', Encoding::US_ASCII
@@ -130,6 +198,7 @@ class CollectionTest < ActiveSupport::TestCase
test "older versions' modified_at indicate when they're created" do
Rails.configuration.collection_versioning = true
+ Rails.configuration.preserve_version_if_idle = 0
act_as_user users(:active) do
# Set up initial collection
c = create_collection 'foo', Encoding::US_ASCII
@@ -163,6 +232,7 @@ class CollectionTest < ActiveSupport::TestCase
test "older versions should no be directly updatable" do
Rails.configuration.collection_versioning = true
+ Rails.configuration.preserve_version_if_idle = 0
act_as_user users(:active) do
# Set up initial collection
c = create_collection 'foo', Encoding::US_ASCII
@@ -205,6 +275,7 @@ class CollectionTest < ActiveSupport::TestCase
].each do |attr, first_val, second_val|
test "sync #{attr} with older versions" do
Rails.configuration.collection_versioning = true
+ Rails.configuration.preserve_version_if_idle = 0
act_as_system_user do
# Set up initial collection
c = create_collection 'foo', Encoding::US_ASCII
@@ -246,6 +317,7 @@ class CollectionTest < ActiveSupport::TestCase
].each do |versioning, attr, val, new_version_expected|
test "update #{attr} with versioning #{versioning ? '' : 'not '}enabled should #{new_version_expected ? '' : 'not '}create a new version" do
Rails.configuration.collection_versioning = versioning
+ Rails.configuration.preserve_version_if_idle = 0
act_as_user users(:active) do
# Create initial collection
c = create_collection 'foo', Encoding::US_ASCII
@@ -280,6 +352,7 @@ class CollectionTest < ActiveSupport::TestCase
test 'with versioning enabled, simultaneous updates increment version correctly' do
Rails.configuration.collection_versioning = true
+ Rails.configuration.preserve_version_if_idle = 0
act_as_user users(:active) do
# Create initial collection
col = create_collection 'foo', Encoding::US_ASCII
commit 647511030800d228feb6955dfab9cb0a26cbfcfb
Author: Lucas Di Pentima <ldipentima at veritasgenetics.com>
Date: Mon Oct 1 14:32:12 2018 -0300
13561: Old collection version's modified_at reflects version's create time.
Don't update this field when syncing past versions' fields with selected
current updates.
Also, keep created_at the same as the current version when snapshotting.
Arvados-DCO-1.1-Signed-off-by: Lucas Di Pentima <ldipentima at veritasgenetics.com>
diff --git a/services/api/app/models/arvados_model.rb b/services/api/app/models/arvados_model.rb
index c67a3961d..4ba4ac771 100644
--- a/services/api/app/models/arvados_model.rb
+++ b/services/api/app/models/arvados_model.rb
@@ -537,12 +537,12 @@ class ArvadosModel < ActiveRecord::Base
def update_modified_by_fields
current_time = db_current_time
- self.created_at = created_at_was || current_time
+ self.created_at ||= created_at_was || current_time
self.updated_at = current_time
self.owner_uuid ||= current_default_owner if self.respond_to? :owner_uuid=
- self.modified_at = current_time
if !anonymous_updater
self.modified_by_user_uuid = current_user ? current_user.uuid : nil
+ self.modified_at = current_time
end
self.modified_by_client_uuid = current_api_client ? current_api_client.uuid : nil
true
diff --git a/services/api/app/models/collection.rb b/services/api/app/models/collection.rb
index f051fb344..025811cf8 100644
--- a/services/api/app/models/collection.rb
+++ b/services/api/app/models/collection.rb
@@ -220,7 +220,7 @@ class Collection < ArvadosModel
self.current_version_uuid ||= self.uuid
end
- def save!
+ def save! *args
if !Rails.configuration.collection_versioning || new_record? || (!self.changes.include?('uuid') && current_version_uuid != uuid)
return super
end
@@ -256,7 +256,9 @@ class Collection < ArvadosModel
c.attributes = updates
# Use a different validation context to skip the 'old_versions_cannot_be_updated'
# validator, as on this case it is legal to update some fields.
- c.save(context: :update_old_versions)
+ leave_modified_by_user_alone do
+ c.save(context: :update_old_versions)
+ end
end
# Also update current object just in case a new version will be created,
# as it has to receive the same values for the synced attributes.
@@ -268,6 +270,7 @@ class Collection < ArvadosModel
# Create a snapshot of the original collection
snapshot = self.dup
snapshot.uuid = nil # Reset UUID so it's created as a new record
+ snapshot.created_at = created_at
# Update current version number
self.version += 1
end
diff --git a/services/api/test/unit/collection_test.rb b/services/api/test/unit/collection_test.rb
index 31c76efa3..569e589b2 100644
--- a/services/api/test/unit/collection_test.rb
+++ b/services/api/test/unit/collection_test.rb
@@ -128,9 +128,42 @@ class CollectionTest < ActiveSupport::TestCase
end
end
+ test "older versions' modified_at indicate when they're created" do
+ Rails.configuration.collection_versioning = true
+ act_as_user users(:active) do
+ # Set up initial collection
+ c = create_collection 'foo', Encoding::US_ASCII
+ assert c.valid?
+ # Make changes so that a new version is created
+ c.update_attributes!({'name' => 'bar'})
+ c.reload
+ assert_equal 2, c.version
+ # Get the old version
+ c_old = Collection.where(current_version_uuid: c.uuid, version: 1).first
+ assert_not_nil c_old
+
+ version_creation_datetime = c_old.modified_at.to_f
+ assert_equal c.created_at.to_f, c_old.created_at.to_f
+ # Current version is updated just a few milliseconds before the version is
+ # saved on the database.
+ assert_operator c.modified_at.to_f, :<, version_creation_datetime
+
+ # Make update on current version so old version get the attribute synced;
+ # its modified_at should not change.
+ new_replication = 3
+ c.update_attributes!({'replication_desired' => new_replication})
+ c.reload
+ assert_equal new_replication, c.replication_desired
+ c_old.reload
+ assert_equal new_replication, c_old.replication_desired
+ assert_equal version_creation_datetime, c_old.modified_at.to_f
+ assert_operator c.modified_at.to_f, :>, c_old.modified_at.to_f
+ end
+ end
+
test "older versions should no be directly updatable" do
Rails.configuration.collection_versioning = true
- act_as_system_user do
+ act_as_user users(:active) do
# Set up initial collection
c = create_collection 'foo', Encoding::US_ASCII
assert c.valid?
@@ -213,7 +246,7 @@ class CollectionTest < ActiveSupport::TestCase
].each do |versioning, attr, val, new_version_expected|
test "update #{attr} with versioning #{versioning ? '' : 'not '}enabled should #{new_version_expected ? '' : 'not '}create a new version" do
Rails.configuration.collection_versioning = versioning
- act_as_system_user do
+ act_as_user users(:active) do
# Create initial collection
c = create_collection 'foo', Encoding::US_ASCII
assert c.valid?
@@ -247,7 +280,7 @@ class CollectionTest < ActiveSupport::TestCase
test 'with versioning enabled, simultaneous updates increment version correctly' do
Rails.configuration.collection_versioning = true
- act_as_system_user do
+ act_as_user users(:active) do
# Create initial collection
col = create_collection 'foo', Encoding::US_ASCII
assert col.valid?
commit fb61bedcbc49d54708410ed394da133440a9d78f
Author: Lucas Di Pentima <ldipentima at veritasgenetics.com>
Date: Sat Sep 29 10:20:24 2018 -0300
13561: Avoid old versions to be updated, with test.
Arvados-DCO-1.1-Signed-off-by: Lucas Di Pentima <ldipentima at veritasgenetics.com>
diff --git a/services/api/app/models/collection.rb b/services/api/app/models/collection.rb
index 61946f82b..f051fb344 100644
--- a/services/api/app/models/collection.rb
+++ b/services/api/app/models/collection.rb
@@ -27,6 +27,7 @@ class Collection < ArvadosModel
validate :ensure_pdh_matches_manifest_text
validate :ensure_storage_classes_desired_is_not_empty
validate :ensure_storage_classes_contain_non_empty_strings
+ validate :old_versions_cannot_be_updated, on: :update
before_save :set_file_names
before_create :set_current_version_uuid
@@ -252,7 +253,10 @@ class Collection < ArvadosModel
end
end
Collection.where('current_version_uuid = ? AND uuid != ?', uuid, uuid).each do |c|
- c.update_attributes!(updates)
+ c.attributes = updates
+ # Use a different validation context to skip the 'old_versions_cannot_be_updated'
+ # validator, as on this case it is legal to update some fields.
+ c.save(context: :update_old_versions)
end
# Also update current object just in case a new version will be created,
# as it has to receive the same values for the synced attributes.
@@ -585,4 +589,12 @@ class Collection < ArvadosModel
end
end
end
+
+ def old_versions_cannot_be_updated
+ # We check for the '_was' values just in case the update operation
+ # includes a change on current_version_uuid or uuid.
+ if current_version_uuid_was != uuid_was
+ raise ArvadosModel::PermissionDeniedError.new("previous versions cannot be updated")
+ end
+ end
end
diff --git a/services/api/test/unit/collection_test.rb b/services/api/test/unit/collection_test.rb
index e3c2a999c..31c76efa3 100644
--- a/services/api/test/unit/collection_test.rb
+++ b/services/api/test/unit/collection_test.rb
@@ -128,6 +128,42 @@ class CollectionTest < ActiveSupport::TestCase
end
end
+ test "older versions should no be directly updatable" do
+ Rails.configuration.collection_versioning = true
+ act_as_system_user do
+ # Set up initial collection
+ c = create_collection 'foo', Encoding::US_ASCII
+ assert c.valid?
+ # Make changes so that a new version is created
+ c.update_attributes!({'name' => 'bar'})
+ c.reload
+ assert_equal 2, c.version
+ # Get the old version
+ c_old = Collection.where(current_version_uuid: c.uuid, version: 1).first
+ assert_not_nil c_old
+ # With collection versioning still being enabled, try to update
+ assert_raises ArvadosModel::PermissionDeniedError do
+ c_old.update_attributes(name: 'this was foo')
+ end
+ c_old.reload
+ assert_equal 'foo', c_old.name
+ # Try to fool the validator attempting to make c_old to look like a
+ # current version, it should also fail.
+ assert_raises ArvadosModel::PermissionDeniedError do
+ c_old.update_attributes(current_version_uuid: c_old.uuid)
+ end
+ c_old.reload
+ assert_equal c.uuid, c_old.current_version_uuid
+ # Now disable collection versioning, it should behave the same way
+ Rails.configuration.collection_versioning = false
+ assert_raises ArvadosModel::PermissionDeniedError do
+ c_old.update_attributes(name: 'this was foo')
+ end
+ c_old.reload
+ assert_equal 'foo', c_old.name
+ end
+ end
+
[
['owner_uuid', 'zzzzz-tpzed-d9tiejq69daie8f', 'zzzzz-tpzed-xurymjxw79nv3jz'],
['replication_desired', 2, 3],
commit be8fbfd594717232c4dc7c4d16cdf3bde1137ee0
Author: Lucas Di Pentima <ldipentima at veritasgenetics.com>
Date: Tue Sep 25 18:44:56 2018 -0300
13561: Sync selected fields changes with older versions, with tests.
Arvados-DCO-1.1-Signed-off-by: Lucas Di Pentima <ldipentima at veritasgenetics.com>
diff --git a/services/api/app/models/collection.rb b/services/api/app/models/collection.rb
index 7e1cd4aff..61946f82b 100644
--- a/services/api/app/models/collection.rb
+++ b/services/api/app/models/collection.rb
@@ -220,32 +220,63 @@ class Collection < ArvadosModel
end
def save!
- if !Rails.configuration.collection_versioning || new_record?
+ if !Rails.configuration.collection_versioning || new_record? || (!self.changes.include?('uuid') && current_version_uuid != uuid)
return super
end
changes = self.changes
- versionable_updates = ['manifest_text', 'description', 'properties', 'name']
- if (changes.keys & versionable_updates).empty?
- # Updates don't include interesting attributes, don't save a new snapshot.
+ # Updates that will be synced with older versions
+ synced_updates = ['uuid', 'owner_uuid', 'delete_at', 'trash_at', 'is_trashed',
+ 'replication_desired', 'storage_classes_desired'] & changes.keys
+ # Updates that will produce a new version
+ versionable_updates = ['manifest_text', 'description', 'properties', 'name'] & changes.keys
+
+ if versionable_updates.empty? && synced_updates.empty?
+ # Updates don't include interesting attributes, so don't save a new snapshot nor
+ # sync older versions.
return super
end
- # Create a snapshot of the current collection before saving.
- # Does row locking because 'version' is incremented.
+
+ # Does row locking (transaction is implicit) because 'version'
+ # may be incremented and the older versions synced.
+ # Note that 'with_lock' reloads the object after locking.
with_lock do
- # Note that 'with_lock' reloads the object after locking.
- # Create a snapshot of the original collection
- snapshot = self.dup
- snapshot.uuid = nil # Reset UUID so it's created as a new record
+ # Sync older versions.
+ if !synced_updates.empty?
+ updates = {}
+ synced_updates.each do |attr|
+ if attr == 'uuid'
+ # Point old versions to current version's new UUID
+ updates['current_version_uuid'] = changes[attr].last
+ else
+ updates[attr] = changes[attr].last
+ end
+ end
+ Collection.where('current_version_uuid = ? AND uuid != ?', uuid, uuid).each do |c|
+ c.update_attributes!(updates)
+ end
+ # Also update current object just in case a new version will be created,
+ # as it has to receive the same values for the synced attributes.
+ self.attributes = updates
+ end
+ snapshot = nil
+ # Make a new version if applicable.
+ if !versionable_updates.empty?
+ # Create a snapshot of the original collection
+ snapshot = self.dup
+ snapshot.uuid = nil # Reset UUID so it's created as a new record
+ # Update current version number
+ self.version += 1
+ end
# Restore requested changes on the current version
changes.keys.each do |attr|
next if attr == 'version'
self.attributes = {attr => changes[attr].last}
end
- # Update current version number & save first to avoid index collision
- self.version += 1
+ # Save current version first to avoid index collision
super
- # Save the snapshot with previous state
- snapshot.save!
+ # Save the snapshot with previous state (if applicable)
+ snapshot.andand.save!
+ return true
end
end
diff --git a/services/api/test/unit/collection_test.rb b/services/api/test/unit/collection_test.rb
index ee17445a1..e3c2a999c 100644
--- a/services/api/test/unit/collection_test.rb
+++ b/services/api/test/unit/collection_test.rb
@@ -106,17 +106,76 @@ class CollectionTest < ActiveSupport::TestCase
end
end
+ test "uuid updates on current version make older versions update their pointers" do
+ Rails.configuration.collection_versioning = true
+ act_as_system_user do
+ # Set up initial collection
+ c = create_collection 'foo', Encoding::US_ASCII
+ assert c.valid?
+ assert_equal 1, c.version
+ # Make changes so that a new version is created
+ c.update_attributes!({'name' => 'bar'})
+ c.reload
+ assert_equal 2, c.version
+ assert_equal 2, Collection.where(current_version_uuid: c.uuid).count
+ new_uuid = 'zzzzz-4zz18-somefakeuuidnow'
+ assert_empty Collection.where(uuid: new_uuid)
+ # Update UUID on current version, check that both collections point to it
+ c.update_attributes!({'uuid' => new_uuid})
+ c.reload
+ assert_equal new_uuid, c.uuid
+ assert_equal 2, Collection.where(current_version_uuid: new_uuid).count
+ end
+ end
+
+ [
+ ['owner_uuid', 'zzzzz-tpzed-d9tiejq69daie8f', 'zzzzz-tpzed-xurymjxw79nv3jz'],
+ ['replication_desired', 2, 3],
+ ['storage_classes_desired', ['hot'], ['archive']],
+ ['is_trashed', true, false],
+ ].each do |attr, first_val, second_val|
+ test "sync #{attr} with older versions" do
+ Rails.configuration.collection_versioning = true
+ act_as_system_user do
+ # Set up initial collection
+ c = create_collection 'foo', Encoding::US_ASCII
+ assert c.valid?
+ assert_equal 1, c.version
+ assert_not_equal first_val, c.attributes[attr]
+ # Make changes so that a new version is created and a synced field is
+ # updated on both
+ c.update_attributes!({'name' => 'bar', attr => first_val})
+ c.reload
+ assert_equal 2, c.version
+ assert_equal first_val, c.attributes[attr]
+ assert_equal 2, Collection.where(current_version_uuid: c.uuid).count
+ assert_equal first_val, Collection.where(current_version_uuid: c.uuid, version: 1).first.attributes[attr]
+ # Only make an update on the same synced field & check that the previously
+ # created version also gets it.
+ c.update_attributes!({attr => second_val})
+ c.reload
+ assert_equal 2, c.version
+ assert_equal second_val, c.attributes[attr]
+ assert_equal 2, Collection.where(current_version_uuid: c.uuid).count
+ assert_equal second_val, Collection.where(current_version_uuid: c.uuid, version: 1).first.attributes[attr]
+ end
+ end
+ end
+
[
- [false, 'name', 'bar'],
- [false, 'description', 'The quick brown fox jumps over the lazy dog'],
- [false, 'properties', {'new_version' => true}],
- [false, 'manifest_text', ". d41d8cd98f00b204e9800998ecf8427e 0:0:foo.txt\n"],
- [true, 'name', 'bar'],
- [true, 'description', 'The quick brown fox jumps over the lazy dog'],
- [true, 'properties', {'new_version' => true}],
- [true, 'manifest_text', ". d41d8cd98f00b204e9800998ecf8427e 0:0:foo.txt\n"],
- ].each do |versioning, attr, val|
- test "update collection #{attr} with versioning #{versioning ? '' : 'not '}enabled" do
+ [false, 'name', 'bar', false],
+ [false, 'description', 'The quick brown fox jumps over the lazy dog', false],
+ [false, 'properties', {'new_version' => true}, false],
+ [false, 'manifest_text', ". d41d8cd98f00b204e9800998ecf8427e 0:0:foo.txt\n", false],
+ [true, 'name', 'bar', true],
+ [true, 'description', 'The quick brown fox jumps over the lazy dog', true],
+ [true, 'properties', {'new_version' => true}, true],
+ [true, 'manifest_text', ". d41d8cd98f00b204e9800998ecf8427e 0:0:foo.txt\n", true],
+ # Non-versionable attribute updates shouldn't create new versions
+ [true, 'replication_desired', 5, false],
+ [false, 'replication_desired', 5, false],
+ ].each do |versioning, attr, val, new_version_expected|
+ test "update #{attr} with versioning #{versioning ? '' : 'not '}enabled should #{new_version_expected ? '' : 'not '}create a new version" do
Rails.configuration.collection_versioning = versioning
act_as_system_user do
# Create initial collection
@@ -131,17 +190,18 @@ class CollectionTest < ActiveSupport::TestCase
# Update attribute and check if version number should be incremented
old_value = c.attributes[attr]
c.update_attributes!({attr => val})
- assert_equal versioning, c.version == 2
+ assert_equal new_version_expected, c.version == 2
assert_equal val, c.attributes[attr]
- if versioning
+ if versioning && new_version_expected
# Search for the snapshot & previous value
assert_equal 2, Collection.where(current_version_uuid: c.uuid).count
s = Collection.where(current_version_uuid: c.uuid, version: 1).first
assert_not_nil s
assert_equal old_value, s.attributes[attr]
else
- # If versioning is disabled, only the current version should exist
+ # If versioning is disabled or no versionable attribute was updated,
+ # only the current version should exist
assert_equal 1, Collection.where(current_version_uuid: c.uuid).count
assert_equal c, Collection.where(current_version_uuid: c.uuid).first
end
commit be338ff6ecdfbc75e094b3e65134c9a841f3209c
Author: Lucas Di Pentima <ldipentima at veritasgenetics.com>
Date: Mon Sep 24 17:29:19 2018 -0300
13561: Lock row when saving a new collection version, update tests.
Arvados-DCO-1.1-Signed-off-by: Lucas Di Pentima <ldipentima at veritasgenetics.com>
diff --git a/services/api/app/models/collection.rb b/services/api/app/models/collection.rb
index 502586e3e..7e1cd4aff 100644
--- a/services/api/app/models/collection.rb
+++ b/services/api/app/models/collection.rb
@@ -219,30 +219,33 @@ class Collection < ArvadosModel
self.current_version_uuid ||= self.uuid
end
- def save *arg
+ def save!
if !Rails.configuration.collection_versioning || new_record?
return super
end
- versionable_updates = ['manifest_text', 'description', 'properties', 'name'] & self.changed_attributes.keys
- if versionable_updates.empty?
+ changes = self.changes
+ versionable_updates = ['manifest_text', 'description', 'properties', 'name']
+ if (changes.keys & versionable_updates).empty?
+ # Updates don't include interesting attributes, don't save a new snapshot.
return super
end
- # Create a snapshot of the current collection before saving
- Collection.transaction do
- attrs = {}
- # Collect attributes with pre-update values
- versionable_updates.each do |attr|
- attrs[attr] = self.changed_attributes[attr]
- end
- # Reset UUID
- attrs[:uuid] = nil
+ # Create a snapshot of the current collection before saving.
+ # Does row locking because 'version' is incremented.
+ with_lock do
+ # Note that 'with_lock' reloads the object after locking.
+ # Create a snapshot of the original collection
snapshot = self.dup
- # Update current version number & save
+ snapshot.uuid = nil # Reset UUID so it's created as a new record
+ # Restore requested changes on the current version
+ changes.keys.each do |attr|
+ next if attr == 'version'
+ self.attributes = {attr => changes[attr].last}
+ end
+ # Update current version number & save first to avoid index collision
self.version += 1
super
- # Save the snapshot with required attributes
- snapshot.update_attributes!(attrs)
- return true
+ # Save the snapshot with previous state
+ snapshot.save!
end
end
diff --git a/services/api/test/unit/collection_test.rb b/services/api/test/unit/collection_test.rb
index f745ca429..ee17445a1 100644
--- a/services/api/test/unit/collection_test.rb
+++ b/services/api/test/unit/collection_test.rb
@@ -116,7 +116,7 @@ class CollectionTest < ActiveSupport::TestCase
[true, 'properties', {'new_version' => true}],
[true, 'manifest_text', ". d41d8cd98f00b204e9800998ecf8427e 0:0:foo.txt\n"],
].each do |versioning, attr, val|
- test "collection's #{attr} update with versioning #{versioning ? '' : 'not '}enabled" do
+ test "update collection #{attr} with versioning #{versioning ? '' : 'not '}enabled" do
Rails.configuration.collection_versioning = versioning
act_as_system_user do
# Create initial collection
@@ -130,9 +130,9 @@ class CollectionTest < ActiveSupport::TestCase
# Update attribute and check if version number should be incremented
old_value = c.attributes[attr]
- c.update_attribute attr, val
- assert_equal val, c.attributes[attr]
+ c.update_attributes!({attr => val})
assert_equal versioning, c.version == 2
+ assert_equal val, c.attributes[attr]
if versioning
# Search for the snapshot & previous value
@@ -149,6 +149,29 @@ class CollectionTest < ActiveSupport::TestCase
end
end
+ test 'with versioning enabled, simultaneous updates increment version correctly' do
+ Rails.configuration.collection_versioning = true
+ act_as_system_user do
+ # Create initial collection
+ col = create_collection 'foo', Encoding::US_ASCII
+ assert col.valid?
+ assert_equal 1, col.version
+
+ # Simulate simultaneous updates
+ c1 = Collection.where(uuid: col.uuid).first
+ assert_equal 1, c1.version
+ c1.name = 'bar'
+ c2 = Collection.where(uuid: col.uuid).first
+ c2.description = 'foo collection'
+ c1.save!
+ assert_equal 1, c2.version
+ # with_lock forces a reload, so this shouldn't produce an unique violation error
+ c2.save!
+ assert_equal 3, c2.version
+ assert_equal 'foo collection', c2.description
+ end
+ end
+
test 'create and update collection and verify file_names' do
act_as_system_user do
c = create_collection 'foo', Encoding::US_ASCII
commit 737dcc58241a06e32615624877d3301b90574227
Author: Lucas Di Pentima <ldipentima at veritasgenetics.com>
Date: Fri Sep 21 13:31:08 2018 -0300
13561: Add missing copyright notices on migrations
Arvados-DCO-1.1-Signed-off-by: Lucas Di Pentima <ldipentima at veritasgenetics.com>
diff --git a/services/api/db/migrate/20180824152014_add_md5_index_to_containers.rb b/services/api/db/migrate/20180824152014_add_md5_index_to_containers.rb
index a58932e35..82b216351 100644
--- a/services/api/db/migrate/20180824152014_add_md5_index_to_containers.rb
+++ b/services/api/db/migrate/20180824152014_add_md5_index_to_containers.rb
@@ -1,3 +1,7 @@
+# Copyright (C) The Arvados Authors. All rights reserved.
+#
+# SPDX-License-Identifier: AGPL-3.0
+
class AddMd5IndexToContainers < ActiveRecord::Migration
def up
ActiveRecord::Base.connection.execute 'CREATE INDEX index_containers_on_reuse_columns on containers (md5(command), cwd, md5(environment), output_path, container_image, md5(mounts), secret_mounts_md5, md5(runtime_constraints))'
diff --git a/services/api/db/migrate/20180904110712_add_runtime_status_to_containers.rb b/services/api/db/migrate/20180904110712_add_runtime_status_to_containers.rb
index 755c7c89e..4c963e6fd 100644
--- a/services/api/db/migrate/20180904110712_add_runtime_status_to_containers.rb
+++ b/services/api/db/migrate/20180904110712_add_runtime_status_to_containers.rb
@@ -1,3 +1,7 @@
+# Copyright (C) The Arvados Authors. All rights reserved.
+#
+# SPDX-License-Identifier: AGPL-3.0
+
class AddRuntimeStatusToContainers < ActiveRecord::Migration
def change
add_column :containers, :runtime_status, :jsonb, default: {}
diff --git a/services/api/db/migrate/20180913175443_add_version_info_to_collections.rb b/services/api/db/migrate/20180913175443_add_version_info_to_collections.rb
index b5378d3a1..a624dd9af 100644
--- a/services/api/db/migrate/20180913175443_add_version_info_to_collections.rb
+++ b/services/api/db/migrate/20180913175443_add_version_info_to_collections.rb
@@ -1,3 +1,7 @@
+# Copyright (C) The Arvados Authors. All rights reserved.
+#
+# SPDX-License-Identifier: AGPL-3.0
+
class AddVersionInfoToCollections < ActiveRecord::Migration
def change
# Do changes in bulk to save time on huge tables
diff --git a/services/api/db/migrate/20180915155335_set_current_version_uuid_on_collections.rb b/services/api/db/migrate/20180915155335_set_current_version_uuid_on_collections.rb
index b205eae89..12a08e07d 100644
--- a/services/api/db/migrate/20180915155335_set_current_version_uuid_on_collections.rb
+++ b/services/api/db/migrate/20180915155335_set_current_version_uuid_on_collections.rb
@@ -1,3 +1,7 @@
+# Copyright (C) The Arvados Authors. All rights reserved.
+#
+# SPDX-License-Identifier: AGPL-3.0
+
class SetCurrentVersionUuidOnCollections < ActiveRecord::Migration
def up
# Set the current version uuid as itself
diff --git a/services/api/db/migrate/20180919001158_recreate_collection_unique_name_index.rb b/services/api/db/migrate/20180919001158_recreate_collection_unique_name_index.rb
index bb921d4e6..640395618 100644
--- a/services/api/db/migrate/20180919001158_recreate_collection_unique_name_index.rb
+++ b/services/api/db/migrate/20180919001158_recreate_collection_unique_name_index.rb
@@ -1,3 +1,7 @@
+# Copyright (C) The Arvados Authors. All rights reserved.
+#
+# SPDX-License-Identifier: AGPL-3.0
+
class RecreateCollectionUniqueNameIndex < ActiveRecord::Migration
def up
Collection.transaction do
commit dbfe1d83ff4e77edc77a562022a999e9ba9e2e2b
Author: Lucas Di Pentima <ldipentima at veritasgenetics.com>
Date: Fri Sep 21 13:18:02 2018 -0300
13561: Add basic support for collection versioning at the model level.
* Update "unique name" index to ignore collection records that are old versions
* Add tests
* Update collection fixtures
Arvados-DCO-1.1-Signed-off-by: Lucas Di Pentima <ldipentima at veritasgenetics.com>
diff --git a/services/api/app/models/collection.rb b/services/api/app/models/collection.rb
index 85b12a377..502586e3e 100644
--- a/services/api/app/models/collection.rb
+++ b/services/api/app/models/collection.rb
@@ -28,6 +28,7 @@ class Collection < ArvadosModel
validate :ensure_storage_classes_desired_is_not_empty
validate :ensure_storage_classes_contain_non_empty_strings
before_save :set_file_names
+ before_create :set_current_version_uuid
api_accessible :user, extend: :common do |t|
t.add :name
@@ -206,6 +207,45 @@ class Collection < ArvadosModel
self.manifest_text ||= ''
end
+ def skip_uuid_existence_check
+ # Avoid checking the existence of current_version_uuid, as it's
+ # assigned on creation of a new 'current version' collection, so
+ # the collection's UUID only lives on memory when the validation check
+ # is performed.
+ ['current_version_uuid']
+ end
+
+ def set_current_version_uuid
+ self.current_version_uuid ||= self.uuid
+ end
+
+ def save *arg
+ if !Rails.configuration.collection_versioning || new_record?
+ return super
+ end
+ versionable_updates = ['manifest_text', 'description', 'properties', 'name'] & self.changed_attributes.keys
+ if versionable_updates.empty?
+ return super
+ end
+ # Create a snapshot of the current collection before saving
+ Collection.transaction do
+ attrs = {}
+ # Collect attributes with pre-update values
+ versionable_updates.each do |attr|
+ attrs[attr] = self.changed_attributes[attr]
+ end
+ # Reset UUID
+ attrs[:uuid] = nil
+ snapshot = self.dup
+ # Update current version number & save
+ self.version += 1
+ super
+ # Save the snapshot with required attributes
+ snapshot.update_attributes!(attrs)
+ return true
+ end
+ end
+
def check_encoding
if manifest_text.encoding.name == 'UTF-8' and manifest_text.valid_encoding?
true
@@ -434,11 +474,11 @@ class Collection < ArvadosModel
end
def self.searchable_columns operator
- super - ["manifest_text"]
+ super - ["manifest_text", "current_version_uuid"]
end
def self.full_text_searchable_columns
- super - ["manifest_text", "storage_classes_desired", "storage_classes_confirmed"]
+ super - ["manifest_text", "storage_classes_desired", "storage_classes_confirmed", "current_version_uuid"]
end
def self.where *args
diff --git a/services/api/config/application.default.yml b/services/api/config/application.default.yml
index 5a1c22951..f480904c4 100644
--- a/services/api/config/application.default.yml
+++ b/services/api/config/application.default.yml
@@ -500,6 +500,10 @@ common:
# keep_web_service_url: https://download.uuid_prefix.arvadosapi.com/
keep_web_service_url: false
+ # If true, enable collection versioning: With every update, a snapshot of the
+ # collection's previous state is created and linked to the current collection.
+ collection_versioning: false
+
development:
force_ssl: false
cache_classes: false
diff --git a/services/api/db/migrate/20180919001158_recreate_collection_unique_name_index.rb b/services/api/db/migrate/20180919001158_recreate_collection_unique_name_index.rb
new file mode 100644
index 000000000..bb921d4e6
--- /dev/null
+++ b/services/api/db/migrate/20180919001158_recreate_collection_unique_name_index.rb
@@ -0,0 +1,23 @@
+class RecreateCollectionUniqueNameIndex < ActiveRecord::Migration
+ def up
+ Collection.transaction do
+ remove_index(:collections,
+ name: 'index_collections_on_owner_uuid_and_name')
+ add_index(:collections, [:owner_uuid, :name],
+ unique: true,
+ where: 'is_trashed = false AND current_version_uuid = uuid',
+ name: 'index_collections_on_owner_uuid_and_name')
+ end
+ end
+
+ def down
+ Collection.transaction do
+ remove_index(:collections,
+ name: 'index_collections_on_owner_uuid_and_name')
+ add_index(:collections, [:owner_uuid, :name],
+ unique: true,
+ where: 'is_trashed = false',
+ name: 'index_collections_on_owner_uuid_and_name')
+ end
+ end
+end
diff --git a/services/api/db/structure.sql b/services/api/db/structure.sql
index d646d609b..de5e2e127 100644
--- a/services/api/db/structure.sql
+++ b/services/api/db/structure.sql
@@ -1829,7 +1829,7 @@ CREATE INDEX index_collections_on_owner_uuid ON public.collections USING btree (
-- Name: index_collections_on_owner_uuid_and_name; Type: INDEX; Schema: public; Owner: -
--
-CREATE UNIQUE INDEX index_collections_on_owner_uuid_and_name ON public.collections USING btree (owner_uuid, name) WHERE (is_trashed = false);
+CREATE UNIQUE INDEX index_collections_on_owner_uuid_and_name ON public.collections USING btree (owner_uuid, name) WHERE ((is_trashed = false) AND ((current_version_uuid)::text = (uuid)::text));
--
@@ -3182,3 +3182,5 @@ INSERT INTO schema_migrations (version) VALUES ('20180913175443');
INSERT INTO schema_migrations (version) VALUES ('20180915155335');
+INSERT INTO schema_migrations (version) VALUES ('20180919001158');
+
diff --git a/services/api/test/fixtures/collections.yml b/services/api/test/fixtures/collections.yml
index 7ff67f82e..3578651ba 100644
--- a/services/api/test/fixtures/collections.yml
+++ b/services/api/test/fixtures/collections.yml
@@ -4,6 +4,7 @@
user_agreement:
uuid: zzzzz-4zz18-t68oksiu9m80s4y
+ current_version_uuid: zzzzz-4zz18-t68oksiu9m80s4y
portable_data_hash: b519d9cb706a29fc7ea24dbea2f05851+93
owner_uuid: zzzzz-tpzed-000000000000000
created_at: 2013-12-26T19:22:54Z
@@ -16,6 +17,7 @@ user_agreement:
collection_owned_by_active:
uuid: zzzzz-4zz18-bv31uwvy3neko21
+ current_version_uuid: zzzzz-4zz18-bv31uwvy3neko21
portable_data_hash: fa7aeb5140e2848d39b416daeef4ffc5+45
owner_uuid: zzzzz-tpzed-xurymjxw79nv3jz
created_at: 2014-02-03T17:22:54Z
@@ -28,6 +30,7 @@ collection_owned_by_active:
foo_file:
uuid: zzzzz-4zz18-znfnqtbbv4spc3w
+ current_version_uuid: zzzzz-4zz18-znfnqtbbv4spc3w
portable_data_hash: 1f4b0bc7583c2a7f9102c395f4ffc5e3+45
owner_uuid: zzzzz-tpzed-000000000000000
created_at: 2015-02-03T17:22:54Z
@@ -40,6 +43,7 @@ foo_file:
bar_file:
uuid: zzzzz-4zz18-ehbhgtheo8909or
+ current_version_uuid: zzzzz-4zz18-ehbhgtheo8909or
portable_data_hash: fa7aeb5140e2848d39b416daeef4ffc5+45
owner_uuid: zzzzz-tpzed-000000000000000
created_at: 2015-02-03T17:22:54Z
@@ -52,6 +56,7 @@ bar_file:
baz_file:
uuid: zzzzz-4zz18-y9vne9npefyxh8g
+ current_version_uuid: zzzzz-4zz18-y9vne9npefyxh8g
portable_data_hash: ea10d51bcf88862dbcc36eb292017dfd+45
owner_uuid: zzzzz-tpzed-000000000000000
created_at: 2014-02-03T17:22:54Z
@@ -64,6 +69,7 @@ baz_file:
w_a_z_file:
uuid: zzzzz-4zz18-25k12570yk134b3
+ current_version_uuid: zzzzz-4zz18-25k12570yk134b3
portable_data_hash: 8706aadd12a0ebc07d74cae88762ba9e+56
owner_uuid: zzzzz-tpzed-xurymjxw79nv3jz
created_at: 2015-02-09T10:53:38Z
@@ -76,6 +82,7 @@ w_a_z_file:
multilevel_collection_1:
uuid: zzzzz-4zz18-pyw8yp9g3pr7irn
+ current_version_uuid: zzzzz-4zz18-pyw8yp9g3pr7irn
portable_data_hash: 1fd08fc162a5c6413070a8bd0bffc818+150
owner_uuid: zzzzz-tpzed-xurymjxw79nv3jz
created_at: 2014-02-03T17:22:54Z
@@ -88,6 +95,7 @@ multilevel_collection_1:
multilevel_collection_2:
uuid: zzzzz-4zz18-45xf9hw1sxkhl6q
+ current_version_uuid: zzzzz-4zz18-45xf9hw1sxkhl6q
# All of this collection's files are deep in subdirectories.
portable_data_hash: 80cf6dd2cf079dd13f272ec4245cb4a8+48
owner_uuid: zzzzz-tpzed-xurymjxw79nv3jz
@@ -101,6 +109,7 @@ multilevel_collection_2:
docker_image:
uuid: zzzzz-4zz18-1v45jub259sjjgb
+ current_version_uuid: zzzzz-4zz18-1v45jub259sjjgb
# This Collection has links with Docker image metadata.
portable_data_hash: fa3c1a9cb6783f85f2ecda037e07b8c3+167
owner_uuid: zzzzz-tpzed-000000000000000
@@ -115,6 +124,7 @@ docker_image:
# tagged docker image with sha256:{hash}.tar filename
docker_image_1_12:
uuid: zzzzz-4zz18-1g4g0vhpjn9wq7i
+ current_version_uuid: zzzzz-4zz18-1g4g0vhpjn9wq7i
portable_data_hash: d740a57097711e08eb9b2a93518f20ab+174
owner_uuid: zzzzz-tpzed-xurymjxw79nv3jz
created_at: 2016-10-19 08:50:45.653552268 Z
@@ -127,6 +137,7 @@ docker_image_1_12:
unlinked_docker_image:
uuid: zzzzz-4zz18-d0d8z5wofvfgwad
+ current_version_uuid: zzzzz-4zz18-d0d8z5wofvfgwad
# This Collection contains a file that looks like a Docker image,
# but has no Docker metadata links pointing to it.
portable_data_hash: 9ae44d5792468c58bcf85ce7353c7027+124
@@ -141,6 +152,7 @@ unlinked_docker_image:
empty:
uuid: zzzzz-4zz18-gs9ooj1h9sd5mde
+ current_version_uuid: zzzzz-4zz18-gs9ooj1h9sd5mde
# Empty collection owned by anonymous_group is added with rake db:seed.
portable_data_hash: d41d8cd98f00b204e9800998ecf8427e+0
owner_uuid: zzzzz-tpzed-000000000000000
@@ -154,6 +166,7 @@ empty:
foo_collection_in_aproject:
uuid: zzzzz-4zz18-fy296fx3hot09f7
+ current_version_uuid: zzzzz-4zz18-fy296fx3hot09f7
portable_data_hash: 1f4b0bc7583c2a7f9102c395f4ffc5e3+45
owner_uuid: zzzzz-j7d0g-v955i6s2oi1cbso
created_at: 2014-04-21 15:37:48 -0400
@@ -164,6 +177,7 @@ foo_collection_in_aproject:
user_agreement_in_anonymously_accessible_project:
uuid: zzzzz-4zz18-uukreo9rbgwsujr
+ current_version_uuid: zzzzz-4zz18-uukreo9rbgwsujr
portable_data_hash: b519d9cb706a29fc7ea24dbea2f05851+93
owner_uuid: zzzzz-j7d0g-zhxawtyetzwc5f0
created_at: 2014-06-13 20:42:26 -0800
@@ -174,6 +188,7 @@ user_agreement_in_anonymously_accessible_project:
public_text_file:
uuid: zzzzz-4zz18-4en62shvi99lxd4
+ current_version_uuid: zzzzz-4zz18-4en62shvi99lxd4
portable_data_hash: 55713e6a34081eb03609e7ad5fcad129+62
owner_uuid: zzzzz-j7d0g-zhxawtyetzwc5f0
created_at: 2015-02-12 16:58:03 -0500
@@ -184,6 +199,7 @@ public_text_file:
baz_collection_name_in_asubproject:
uuid: zzzzz-4zz18-lsitwcf548ui4oe
+ current_version_uuid: zzzzz-4zz18-lsitwcf548ui4oe
portable_data_hash: ea10d51bcf88862dbcc36eb292017dfd+45
owner_uuid: zzzzz-j7d0g-axqo7eu9pwvna1x
created_at: 2014-04-21 15:37:48 -0400
@@ -194,6 +210,7 @@ baz_collection_name_in_asubproject:
empty_collection_name_in_active_user_home_project:
uuid: zzzzz-4zz18-5qa38qghh1j3nvv
+ current_version_uuid: zzzzz-4zz18-5qa38qghh1j3nvv
portable_data_hash: d41d8cd98f00b204e9800998ecf8427e+0
owner_uuid: zzzzz-tpzed-xurymjxw79nv3jz
created_at: 2014-08-06 22:11:51.242392533 Z
@@ -203,6 +220,7 @@ empty_collection_name_in_active_user_home_project:
baz_file_in_asubproject:
uuid: zzzzz-4zz18-0mri2x4u7ftngez
+ current_version_uuid: zzzzz-4zz18-0mri2x4u7ftngez
portable_data_hash: ea10d51bcf88862dbcc36eb292017dfd+45
owner_uuid: zzzzz-j7d0g-axqo7eu9pwvna1x
created_at: 2014-02-03T17:22:54Z
@@ -215,6 +233,7 @@ baz_file_in_asubproject:
collection_to_move_around_in_aproject:
uuid: zzzzz-4zz18-0mri2x4u7ft1234
+ current_version_uuid: zzzzz-4zz18-0mri2x4u7ft1234
portable_data_hash: ea10d51bcf88862dbcc36eb292017dfd+45
owner_uuid: zzzzz-j7d0g-v955i6s2oi1cbso
created_at: 2014-02-03T17:22:54Z
@@ -229,6 +248,7 @@ collection_to_move_around_in_aproject:
# because it is not in default scope
expired_collection:
uuid: zzzzz-4zz18-mto52zx1s7sn3ih
+ current_version_uuid: zzzzz-4zz18-mto52zx1s7sn3ih
portable_data_hash: 0b21a217243bfce5617fb9224b95bcb9+49
owner_uuid: zzzzz-tpzed-xurymjxw79nv3jz
created_at: 2014-02-03T17:22:54Z
@@ -244,6 +264,7 @@ expired_collection:
trashed_on_next_sweep:
uuid: zzzzz-4zz18-4guozfh77ewd2f0
+ current_version_uuid: zzzzz-4zz18-4guozfh77ewd2f0
portable_data_hash: 0b21a217243bfce5617fb9224b95bcb9+49
owner_uuid: zzzzz-tpzed-xurymjxw79nv3jz
created_at: 2016-12-07T22:01:00.123456Z
@@ -261,6 +282,7 @@ trashed_on_next_sweep:
# because it is not in default scope
deleted_on_next_sweep:
uuid: zzzzz-4zz18-3u1p5umicfpqszp
+ current_version_uuid: zzzzz-4zz18-3u1p5umicfpqszp
portable_data_hash: 0b21a217243bfce5617fb9224b95bcb9+49
owner_uuid: zzzzz-tpzed-xurymjxw79nv3jz
created_at: 2016-12-07T22:01:00.234567Z
@@ -276,6 +298,7 @@ deleted_on_next_sweep:
collection_expires_in_future:
uuid: zzzzz-4zz18-padkqo7yb8d9i3j
+ current_version_uuid: zzzzz-4zz18-padkqo7yb8d9i3j
portable_data_hash: 0b21a217243bfce5617fb9224b95bcb9+49
owner_uuid: zzzzz-tpzed-xurymjxw79nv3jz
created_at: 2014-02-03T17:22:54Z
@@ -290,6 +313,7 @@ collection_expires_in_future:
unique_expired_collection:
uuid: zzzzz-4zz18-mto52zx1s7sn3jk
+ current_version_uuid: zzzzz-4zz18-mto52zx1s7sn3jk
portable_data_hash: 4ad199f90029935844dc3f098f4fca2a+49
owner_uuid: zzzzz-tpzed-xurymjxw79nv3jz
created_at: 2014-02-03T17:22:54Z
@@ -305,6 +329,7 @@ unique_expired_collection:
unique_expired_collection2:
uuid: zzzzz-4zz18-mto52zx1s7sn3jr
+ current_version_uuid: zzzzz-4zz18-mto52zx1s7sn3jr
portable_data_hash: 4ad199f90029935844dc3f098f4fca2b+49
owner_uuid: zzzzz-tpzed-000000000000000
created_at: 2014-02-03T17:22:54Z
@@ -326,6 +351,7 @@ unique_expired_collection2:
#
real_log_collection:
uuid: zzzzz-4zz18-op4e2lbej01tcvu
+ current_version_uuid: zzzzz-4zz18-op4e2lbej01tcvu
owner_uuid: zzzzz-tpzed-xurymjxw79nv3jz
created_at: 2014-09-01 12:00:00
modified_at: 2014-09-01 12:00:00
@@ -335,6 +361,7 @@ real_log_collection:
collection_in_home_project_with_same_name_as_in_aproject:
uuid: zzzzz-4zz18-12342x4u7ftabcd
+ current_version_uuid: zzzzz-4zz18-12342x4u7ftabcd
portable_data_hash: ea10d51bcf88862dbcc36eb292017dfd+45
owner_uuid: zzzzz-tpzed-xurymjxw79nv3jz
created_at: 2014-02-03T17:22:54Z
@@ -347,6 +374,7 @@ collection_in_home_project_with_same_name_as_in_aproject:
collection_in_aproject_with_same_name_as_in_home_project:
uuid: zzzzz-4zz18-56782x4u7ftefgh
+ current_version_uuid: zzzzz-4zz18-56782x4u7ftefgh
portable_data_hash: ea10d51bcf88862dbcc36eb292017dfd+45
owner_uuid: zzzzz-j7d0g-v955i6s2oi1cbso
created_at: 2014-02-03T17:22:54Z
@@ -359,6 +387,7 @@ collection_in_aproject_with_same_name_as_in_home_project:
collection_owned_by_foo:
uuid: zzzzz-4zz18-50surkhkbhsp31b
+ current_version_uuid: zzzzz-4zz18-50surkhkbhsp31b
portable_data_hash: ea10d51bcf88862dbcc36eb292017dfd+45
manifest_text: ". 73feffa4b7f6bb68e44cf984c85f6e88+3 0:3:baz\n"
owner_uuid: zzzzz-tpzed-81hsbo6mk8nl05c
@@ -369,6 +398,7 @@ collection_owned_by_foo:
collection_to_remove_from_subproject:
# The Workbench tests remove this from subproject.
uuid: zzzzz-4zz18-subprojgonecoll
+ current_version_uuid: zzzzz-4zz18-subprojgonecoll
portable_data_hash: 2386ca6e3fffd4be5e197a72c6c80fb2+51
manifest_text: ". 8258b505536a9ab47baa2f4281cb932a+9 0:9:missingno\n"
owner_uuid: zzzzz-j7d0g-axqo7eu9pwvna1x
@@ -378,6 +408,7 @@ collection_to_remove_from_subproject:
collection_with_files_in_subdir:
uuid: zzzzz-4zz18-filesinsubdir00
+ current_version_uuid: zzzzz-4zz18-filesinsubdir00
name: collection_files_in_subdir
portable_data_hash: 85877ca2d7e05498dd3d109baf2df106+95
owner_uuid: zzzzz-tpzed-user1withloadab
@@ -390,6 +421,7 @@ collection_with_files_in_subdir:
graph_test_collection1:
uuid: zzzzz-4zz18-bv31uwvy3neko22
+ current_version_uuid: zzzzz-4zz18-bv31uwvy3neko22
owner_uuid: zzzzz-tpzed-xurymjxw79nv3jz
portable_data_hash: fa7aeb5140e2848d39b416daeef4ffc5+45
manifest_text: ". 37b51d194a7513e45b56f6524f2d51f2+3 0:3:bar\n"
@@ -399,6 +431,7 @@ graph_test_collection1:
graph_test_collection2:
uuid: zzzzz-4zz18-uukreo9rbgwsujx
+ current_version_uuid: zzzzz-4zz18-uukreo9rbgwsujx
owner_uuid: zzzzz-tpzed-xurymjxw79nv3jz
portable_data_hash: 65b17c95fdbc9800fc48acda4e9dcd0b+93
manifest_text: ". 6a4ff0499484c6c79c95cd8c566bd25f+249025 0:249025:FOO_General_Public_License,_version_3.pdf\n"
@@ -408,6 +441,7 @@ graph_test_collection2:
graph_test_collection3:
uuid: zzzzz-4zz18-uukreo9rbgwsujj
+ current_version_uuid: zzzzz-4zz18-uukreo9rbgwsujj
owner_uuid: zzzzz-tpzed-xurymjxw79nv3jz
portable_data_hash: ea10d51bcf88862dbcc36eb292017dfd+45
manifest_text: ". 73feffa4b7f6bb68e44cf984c85f6e88+3 0:3:baz\n"
@@ -417,6 +451,7 @@ graph_test_collection3:
collection_1_owned_by_fuse:
uuid: zzzzz-4zz18-ovx05bfzormx3bg
+ current_version_uuid: zzzzz-4zz18-ovx05bfzormx3bg
portable_data_hash: fa7aeb5140e2848d39b416daeef4ffc5+45
owner_uuid: zzzzz-tpzed-0fusedrivertest
created_at: 2014-02-03T17:22:54Z
@@ -429,6 +464,7 @@ collection_1_owned_by_fuse:
collection_2_owned_by_fuse:
uuid: zzzzz-4zz18-8ubpy4w74twtwzr
+ current_version_uuid: zzzzz-4zz18-8ubpy4w74twtwzr
portable_data_hash: 1f4b0bc7583c2a7f9102c395f4ffc5e3+45
owner_uuid: zzzzz-tpzed-0fusedrivertest
created_at: 2014-02-03T17:22:54Z
@@ -441,6 +477,7 @@ collection_2_owned_by_fuse:
collection_in_fuse_project:
uuid: zzzzz-4zz18-vx4mtkjqfrb534f
+ current_version_uuid: zzzzz-4zz18-vx4mtkjqfrb534f
portable_data_hash: ea10d51bcf88862dbcc36eb292017dfd+45
owner_uuid: zzzzz-j7d0g-0000ownedbyfuse
created_at: 2014-02-03T17:22:54Z
@@ -453,6 +490,7 @@ collection_in_fuse_project:
collection_with_no_name_in_aproject:
uuid: zzzzz-4zz18-00000nonamecoll
+ current_version_uuid: zzzzz-4zz18-00000nonamecoll
portable_data_hash: 1f4b0bc7583c2a7f9102c395f4ffc5e3+45
owner_uuid: zzzzz-j7d0g-v955i6s2oi1cbso
created_at: 2014-04-21 15:37:48 -0400
@@ -462,6 +500,7 @@ collection_with_no_name_in_aproject:
collection_to_search_for_in_aproject:
uuid: zzzzz-4zz18-abcd6fx123409f7
+ current_version_uuid: zzzzz-4zz18-abcd6fx123409f7
portable_data_hash: 1f4b0bc7583c2a7f9102c395f4ffc5e3+45
owner_uuid: zzzzz-j7d0g-v955i6s2oi1cbso
created_at: 2014-04-21 15:37:48 -0400
@@ -472,6 +511,7 @@ collection_to_search_for_in_aproject:
upload_sandbox:
uuid: zzzzz-4zz18-js48y3ykkfdfjd3
+ current_version_uuid: zzzzz-4zz18-js48y3ykkfdfjd3
owner_uuid: zzzzz-tpzed-xurymjxw79nv3jz
created_at: 2014-12-09 15:03:16
modified_by_user_uuid: zzzzz-tpzed-xurymjxw79nv3jz
@@ -483,6 +523,7 @@ upload_sandbox:
collection_with_unique_words_to_test_full_text_search:
uuid: zzzzz-4zz18-mnt690klmb51aud
+ current_version_uuid: zzzzz-4zz18-mnt690klmb51aud
portable_data_hash: fa7aeb5140e2848d39b416daeef4ffc5+45
owner_uuid: zzzzz-tpzed-xurymjxw79nv3jz
created_at: 2014-02-03T17:22:54Z
@@ -495,6 +536,8 @@ collection_with_unique_words_to_test_full_text_search:
description: The quick_brown_fox jumps over the lazy_dog
replication_undesired_unconfirmed:
+ uuid: zzzzz-4zz18-wjxq7uzx2m9jj4a
+ current_version_uuid: zzzzz-4zz18-wjxq7uzx2m9jj4a
owner_uuid: zzzzz-tpzed-xurymjxw79nv3jz
created_at: 2015-02-07 00:19:28.596506247 Z
modified_by_user_uuid: zzzzz-tpzed-xurymjxw79nv3jz
@@ -504,11 +547,12 @@ replication_undesired_unconfirmed:
replication_confirmed_at: ~
replication_confirmed: ~
updated_at: 2015-02-07 00:19:28.596236608 Z
- uuid: zzzzz-4zz18-wjxq7uzx2m9jj4a
manifest_text: ". 37b51d194a7513e45b56f6524f2d51f2+3 0:3:bar\n"
name: replication want=null have=null
replication_desired_2_unconfirmed:
+ uuid: zzzzz-4zz18-3t236wrz4769h7x
+ current_version_uuid: zzzzz-4zz18-3t236wrz4769h7x
owner_uuid: zzzzz-tpzed-xurymjxw79nv3jz
created_at: 2015-02-07 00:21:35.050333515 Z
modified_by_user_uuid: zzzzz-tpzed-xurymjxw79nv3jz
@@ -518,11 +562,12 @@ replication_desired_2_unconfirmed:
replication_confirmed_at: ~
replication_confirmed: ~
updated_at: 2015-02-07 00:21:35.050126576 Z
- uuid: zzzzz-4zz18-3t236wrz4769h7x
manifest_text: ". 37b51d194a7513e45b56f6524f2d51f2+3 0:3:bar\n"
name: replication want=2 have=null
replication_desired_2_confirmed_2:
+ uuid: zzzzz-4zz18-434zv1tnnf2rygp
+ current_version_uuid: zzzzz-4zz18-434zv1tnnf2rygp
owner_uuid: zzzzz-tpzed-xurymjxw79nv3jz
created_at: 2015-02-07 00:19:28.596506247 Z
modified_by_user_uuid: zzzzz-tpzed-xurymjxw79nv3jz
@@ -532,11 +577,12 @@ replication_desired_2_confirmed_2:
replication_confirmed_at: 2015-02-07 00:24:52.983381227 Z
replication_confirmed: 2
updated_at: 2015-02-07 00:24:52.983381227 Z
- uuid: zzzzz-4zz18-434zv1tnnf2rygp
manifest_text: ". acbd18db4cc2f85cedef654fccc4a4d8+3 37b51d194a7513e45b56f6524f2d51f2+3 0:3:foo 3:3:bar\n"
name: replication want=2 have=2
storage_classes_desired_default_unconfirmed:
+ uuid: zzzzz-4zz18-3t236wrz4769tga
+ current_version_uuid: zzzzz-4zz18-3t236wrz4769tga
owner_uuid: zzzzz-tpzed-xurymjxw79nv3jz
created_at: 2015-02-07 00:21:35.050333515 Z
modified_by_user_uuid: zzzzz-tpzed-xurymjxw79nv3jz
@@ -546,11 +592,12 @@ storage_classes_desired_default_unconfirmed:
storage_classes_confirmed_at: ~
storage_classes_confirmed: ~
updated_at: 2015-02-07 00:21:35.050126576 Z
- uuid: zzzzz-4zz18-3t236wrz4769tga
manifest_text: ". 37b51d194a7513e45b56f6524f2d51f2+3 0:3:bar\n"
name: storage classes want=[default] have=[]
storage_classes_desired_default_confirmed_default:
+ uuid: zzzzz-4zz18-3t236wr12769tga
+ current_version_uuid: zzzzz-4zz18-3t236wr12769tga
owner_uuid: zzzzz-tpzed-xurymjxw79nv3jz
created_at: 2015-02-07 00:21:35.050333515 Z
modified_by_user_uuid: zzzzz-tpzed-xurymjxw79nv3jz
@@ -560,11 +607,12 @@ storage_classes_desired_default_confirmed_default:
storage_classes_confirmed_at: 2015-02-07 00:21:35.050126576 Z
storage_classes_confirmed: ["default"]
updated_at: 2015-02-07 00:21:35.050126576 Z
- uuid: zzzzz-4zz18-3t236wr12769tga
manifest_text: ". 37b51d194a7513e45b56f6524f2d51f2+3 0:3:bar\n"
name: storage classes want=[default] have=[default]
storage_classes_desired_archive_confirmed_default:
+ uuid: zzzzz-4zz18-3t236wr12769qqa
+ current_version_uuid: zzzzz-4zz18-3t236wr12769qqa
owner_uuid: zzzzz-tpzed-xurymjxw79nv3jz
created_at: 2015-02-07 00:21:35.050333515 Z
modified_by_user_uuid: zzzzz-tpzed-xurymjxw79nv3jz
@@ -574,12 +622,12 @@ storage_classes_desired_archive_confirmed_default:
storage_classes_confirmed_at: ~
storage_classes_confirmed: ["default"]
updated_at: 2015-02-07 00:21:35.050126576 Z
- uuid: zzzzz-4zz18-3t236wr12769qqa
manifest_text: ". 37b51d194a7513e45b56f6524f2d51f2+3 0:3:bar\n"
name: storage classes want=[archive] have=[default]
collection_with_empty_properties:
uuid: zzzzz-4zz18-emptyproperties
+ current_version_uuid: zzzzz-4zz18-emptyproperties
portable_data_hash: fa7aeb5140e2848d39b416daeef4ffc5+45
owner_uuid: zzzzz-tpzed-xurymjxw79nv3jz
created_at: 2015-02-13T17:22:54Z
@@ -593,6 +641,7 @@ collection_with_empty_properties:
collection_with_one_property:
uuid: zzzzz-4zz18-withoneproperty
+ current_version_uuid: zzzzz-4zz18-withoneproperty
portable_data_hash: fa7aeb5140e2848d39b416daeef4ffc5+45
owner_uuid: zzzzz-tpzed-xurymjxw79nv3jz
created_at: 2015-02-13T17:22:54Z
@@ -608,6 +657,7 @@ collection_with_one_property:
# The following four collections are used to test combining collections with repeated filenames
collection_with_repeated_filenames_and_contents_in_two_dirs_1:
uuid: zzzzz-4zz18-duplicatenames1
+ current_version_uuid: zzzzz-4zz18-duplicatenames1
portable_data_hash: f3a67fad3a19c31c658982fb8158fa58+144
owner_uuid: zzzzz-tpzed-xurymjxw79nv3jz
created_at: 2014-02-03T17:22:54Z
@@ -620,6 +670,7 @@ collection_with_repeated_filenames_and_contents_in_two_dirs_1:
collection_with_repeated_filenames_and_contents_in_two_dirs_2:
uuid: zzzzz-4zz18-duplicatenames2
+ current_version_uuid: zzzzz-4zz18-duplicatenames2
portable_data_hash: f3a67fad3a19c31c658982fb8158fa58+144
owner_uuid: zzzzz-tpzed-xurymjxw79nv3jz
created_at: 2014-02-03T17:22:54Z
@@ -632,6 +683,7 @@ collection_with_repeated_filenames_and_contents_in_two_dirs_2:
foo_and_bar_files_in_dir:
uuid: zzzzz-4zz18-foonbarfilesdir
+ current_version_uuid: zzzzz-4zz18-foonbarfilesdir
portable_data_hash: 6bbac24198d09a93975f60098caf0bdf+62
owner_uuid: zzzzz-tpzed-xurymjxw79nv3jz
created_at: 2014-02-03T17:22:54Z
@@ -644,6 +696,7 @@ foo_and_bar_files_in_dir:
multi_level_to_combine:
uuid: zzzzz-4zz18-pyw8yp9g3ujh45f
+ current_version_uuid: zzzzz-4zz18-pyw8yp9g3ujh45f
portable_data_hash: 7a6ef4c162a5c6413070a8bd0bffc818+150
owner_uuid: zzzzz-tpzed-xurymjxw79nv3jz
created_at: 2014-02-03T17:22:54Z
@@ -657,6 +710,7 @@ multi_level_to_combine:
# collection with several file types to test view icon enabled state in collection show page
collection_with_several_supported_file_types:
uuid: zzzzz-4zz18-supportedtypes1
+ current_version_uuid: zzzzz-4zz18-supportedtypes1
portable_data_hash: 020d82cf7dedb70fd2b7788b5d0634da+269
owner_uuid: zzzzz-tpzed-xurymjxw79nv3jz
created_at: 2014-02-03T17:22:54Z
@@ -669,6 +723,7 @@ collection_with_several_supported_file_types:
collection_with_several_unsupported_file_types:
uuid: zzzzz-4zz18-supportedtypes2
+ current_version_uuid: zzzzz-4zz18-supportedtypes2
portable_data_hash: 71ac42f87464ee5f9fd396d560d400c3+59
owner_uuid: zzzzz-tpzed-xurymjxw79nv3jz
created_at: 2014-02-03T17:22:54Z
@@ -681,6 +736,7 @@ collection_with_several_unsupported_file_types:
collection_not_readable_by_active:
uuid: zzzzz-4zz18-cd42uwvy3neko21
+ current_version_uuid: zzzzz-4zz18-cd42uwvy3neko21
portable_data_hash: bb89eb5140e2848d39b416daeef4ffc5+45
owner_uuid: zzzzz-tpzed-000000000000000
created_at: 2014-02-03T17:22:54Z
@@ -693,6 +749,7 @@ collection_not_readable_by_active:
collection_to_remove_and_rename_files:
uuid: zzzzz-4zz18-a21ux3541sxa8sf
+ current_version_uuid: zzzzz-4zz18-a21ux3541sxa8sf
portable_data_hash: 80cf6dd2cf079dd13f272ec4245cb4a8+48
owner_uuid: zzzzz-tpzed-xurymjxw79nv3jz
created_at: 2014-02-03T17:22:54Z
@@ -705,6 +762,7 @@ collection_to_remove_and_rename_files:
collection_with_tags_owned_by_active:
uuid: zzzzz-4zz18-taggedcolletion
+ current_version_uuid: zzzzz-4zz18-taggedcolletion
portable_data_hash: fa7aeb5140e2848d39b416daeef4ffc5+45
owner_uuid: zzzzz-tpzed-xurymjxw79nv3jz
created_at: 2014-02-03T17:22:54Z
@@ -720,6 +778,7 @@ collection_with_tags_owned_by_active:
trashed_collection_to_test_name_conflict_on_untrash:
uuid: zzzzz-4zz18-trashedcolnamec
+ current_version_uuid: zzzzz-4zz18-trashedcolnamec
portable_data_hash: 80cf6dd2cf079dd13f272ec4245cb4a8+48
owner_uuid: zzzzz-tpzed-xurymjxw79nv3jz
created_at: 2014-02-03T17:22:54Z
@@ -735,6 +794,7 @@ trashed_collection_to_test_name_conflict_on_untrash:
same_name_as_trashed_coll_to_test_name_conflict_on_untrash:
uuid: zzzzz-4zz18-namesameastrash
+ current_version_uuid: zzzzz-4zz18-namesameastrash
portable_data_hash: 80cf6dd2cf079dd13f272ec4245cb4a8+48
owner_uuid: zzzzz-tpzed-xurymjxw79nv3jz
created_at: 2014-02-03T17:22:54Z
@@ -747,6 +807,7 @@ same_name_as_trashed_coll_to_test_name_conflict_on_untrash:
collection_in_trashed_subproject:
uuid: zzzzz-4zz18-trashedproj2col
+ current_version_uuid: zzzzz-4zz18-trashedproj2col
portable_data_hash: 80cf6dd2cf079dd13f272ec4245cb4a8+48
owner_uuid: zzzzz-j7d0g-trashedproject2
created_at: 2014-02-03T17:22:54Z
@@ -759,6 +820,7 @@ collection_in_trashed_subproject:
collection_with_prop1_value1:
uuid: zzzzz-4zz18-withprop1value1
+ current_version_uuid: zzzzz-4zz18-withprop1value1
portable_data_hash: fa7aeb5140e2848d39b416daeef4ffc5+45
owner_uuid: zzzzz-tpzed-xurymjxw79nv3jz
created_at: 2015-02-13T17:22:54Z
@@ -773,6 +835,7 @@ collection_with_prop1_value1:
collection_with_prop1_value2:
uuid: zzzzz-4zz18-withprop1value2
+ current_version_uuid: zzzzz-4zz18-withprop1value2
portable_data_hash: fa7aeb5140e2848d39b416daeef4ffc5+45
owner_uuid: zzzzz-tpzed-xurymjxw79nv3jz
created_at: 2015-02-13T17:22:54Z
@@ -787,6 +850,7 @@ collection_with_prop1_value2:
collection_with_prop1_value3:
uuid: zzzzz-4zz18-withprop1value3
+ current_version_uuid: zzzzz-4zz18-withprop1value3
portable_data_hash: fa7aeb5140e2848d39b416daeef4ffc5+45
owner_uuid: zzzzz-tpzed-xurymjxw79nv3jz
created_at: 2015-02-13T17:22:54Z
@@ -801,6 +865,7 @@ collection_with_prop1_value3:
collection_with_prop1_other1:
uuid: zzzzz-4zz18-withprop1other1
+ current_version_uuid: zzzzz-4zz18-withprop1other1
portable_data_hash: fa7aeb5140e2848d39b416daeef4ffc5+45
owner_uuid: zzzzz-tpzed-xurymjxw79nv3jz
created_at: 2015-02-13T17:22:54Z
@@ -815,6 +880,7 @@ collection_with_prop1_other1:
collection_with_prop2_1:
uuid: zzzzz-4zz18-withprop2value1
+ current_version_uuid: zzzzz-4zz18-withprop2value1
portable_data_hash: fa7aeb5140e2848d39b416daeef4ffc5+45
owner_uuid: zzzzz-tpzed-xurymjxw79nv3jz
created_at: 2015-02-13T17:22:54Z
@@ -829,6 +895,7 @@ collection_with_prop2_1:
collection_with_prop2_5:
uuid: zzzzz-4zz18-withprop2value5
+ current_version_uuid: zzzzz-4zz18-withprop2value5
portable_data_hash: fa7aeb5140e2848d39b416daeef4ffc5+45
owner_uuid: zzzzz-tpzed-xurymjxw79nv3jz
created_at: 2015-02-13T17:22:54Z
@@ -843,6 +910,7 @@ collection_with_prop2_5:
collection_with_uri_prop:
uuid: zzzzz-4zz18-withuripropval1
+ current_version_uuid: zzzzz-4zz18-withuripropval1
portable_data_hash: fa7aeb5140e2848d39b416daeef4ffc5+45
owner_uuid: zzzzz-tpzed-xurymjxw79nv3jz
created_at: 2015-02-13T17:22:54Z
@@ -866,6 +934,7 @@ collection_<%=i%>_of_10:
portable_data_hash: ea10d51bcf88862dbcc36eb292017dfd+45
manifest_text: ". 73feffa4b7f6bb68e44cf984c85f6e88+3 0:3:baz\n"
uuid: zzzzz-4zz18-10gneyn6brkx<%= i.to_s.rjust(3, '0') %>
+ current_version_uuid: zzzzz-4zz18-10gneyn6brkx<%= i.to_s.rjust(3, '0') %>
owner_uuid: zzzzz-j7d0g-0010collections
created_at: <%= i.minute.ago.to_s(:db) %>
modified_at: <%= i.minute.ago.to_s(:db) %>
@@ -878,6 +947,7 @@ collection_<%=i%>_of_201:
portable_data_hash: ea10d51bcf88862dbcc36eb292017dfd+45
manifest_text: ". 73feffa4b7f6bb68e44cf984c85f6e88+3 0:3:baz\n"
uuid: zzzzz-4zz18-201gneyn6brd<%= i.to_s.rjust(3, '0') %>
+ current_version_uuid: zzzzz-4zz18-201gneyn6brd<%= i.to_s.rjust(3, '0') %>
owner_uuid: zzzzz-j7d0g-0201collections
created_at: <%= i.minute.ago.to_s(:db) %>
modified_at: <%= i.minute.ago.to_s(:db) %>
diff --git a/services/api/test/unit/collection_test.rb b/services/api/test/unit/collection_test.rb
index 8b8c48fe1..f745ca429 100644
--- a/services/api/test/unit/collection_test.rb
+++ b/services/api/test/unit/collection_test.rb
@@ -11,7 +11,7 @@ class CollectionTest < ActiveSupport::TestCase
def create_collection name, enc=nil
txt = ". d41d8cd98f00b204e9800998ecf8427e+0 0:0:#{name}.txt\n"
txt.force_encoding(enc) if enc
- return Collection.create(manifest_text: txt)
+ return Collection.create(manifest_text: txt, name: name)
end
test 'accept ASCII manifest_text' do
@@ -106,6 +106,49 @@ class CollectionTest < ActiveSupport::TestCase
end
end
+ [
+ [false, 'name', 'bar'],
+ [false, 'description', 'The quick brown fox jumps over the lazy dog'],
+ [false, 'properties', {'new_version' => true}],
+ [false, 'manifest_text', ". d41d8cd98f00b204e9800998ecf8427e 0:0:foo.txt\n"],
+ [true, 'name', 'bar'],
+ [true, 'description', 'The quick brown fox jumps over the lazy dog'],
+ [true, 'properties', {'new_version' => true}],
+ [true, 'manifest_text', ". d41d8cd98f00b204e9800998ecf8427e 0:0:foo.txt\n"],
+ ].each do |versioning, attr, val|
+ test "collection's #{attr} update with versioning #{versioning ? '' : 'not '}enabled" do
+ Rails.configuration.collection_versioning = versioning
+ act_as_system_user do
+ # Create initial collection
+ c = create_collection 'foo', Encoding::US_ASCII
+ assert c.valid?
+ assert_equal 'foo', c.name
+
+ # Check current version attributes
+ assert_equal 1, c.version
+ assert_equal c.uuid, c.current_version_uuid
+
+ # Update attribute and check if version number should be incremented
+ old_value = c.attributes[attr]
+ c.update_attribute attr, val
+ assert_equal val, c.attributes[attr]
+ assert_equal versioning, c.version == 2
+
+ if versioning
+ # Search for the snapshot & previous value
+ assert_equal 2, Collection.where(current_version_uuid: c.uuid).count
+ s = Collection.where(current_version_uuid: c.uuid, version: 1).first
+ assert_not_nil s
+ assert_equal old_value, s.attributes[attr]
+ else
+ # If versioning is disabled, only the current version should exist
+ assert_equal 1, Collection.where(current_version_uuid: c.uuid).count
+ assert_equal c, Collection.where(current_version_uuid: c.uuid).first
+ end
+ end
+ end
+ end
+
test 'create and update collection and verify file_names' do
act_as_system_user do
c = create_collection 'foo', Encoding::US_ASCII
commit e37b9b6599f427520100aa262bcd65d6596bdbfd
Author: Lucas Di Pentima <ldipentima at veritasgenetics.com>
Date: Fri Sep 14 13:11:42 2018 -0300
13561: Add initial collection version information to the database
Arvados-DCO-1.1-Signed-off-by: Lucas Di Pentima <ldipentima at veritasgenetics.com>
diff --git a/services/api/db/migrate/20180913175443_add_version_info_to_collections.rb b/services/api/db/migrate/20180913175443_add_version_info_to_collections.rb
new file mode 100644
index 000000000..b5378d3a1
--- /dev/null
+++ b/services/api/db/migrate/20180913175443_add_version_info_to_collections.rb
@@ -0,0 +1,10 @@
+class AddVersionInfoToCollections < ActiveRecord::Migration
+ def change
+ # Do changes in bulk to save time on huge tables
+ change_table :collections, :bulk => true do |t|
+ t.string :current_version_uuid
+ t.integer :version, null: false, default: 1
+ t.index [:current_version_uuid, :version], unique: true
+ end
+ end
+end
diff --git a/services/api/db/migrate/20180915155335_set_current_version_uuid_on_collections.rb b/services/api/db/migrate/20180915155335_set_current_version_uuid_on_collections.rb
new file mode 100644
index 000000000..b205eae89
--- /dev/null
+++ b/services/api/db/migrate/20180915155335_set_current_version_uuid_on_collections.rb
@@ -0,0 +1,9 @@
+class SetCurrentVersionUuidOnCollections < ActiveRecord::Migration
+ def up
+ # Set the current version uuid as itself
+ Collection.where(current_version_uuid: nil).update_all("current_version_uuid=uuid")
+ end
+
+ def down
+ end
+end
diff --git a/services/api/db/structure.sql b/services/api/db/structure.sql
index 427c9afb5..d646d609b 100644
--- a/services/api/db/structure.sql
+++ b/services/api/db/structure.sql
@@ -172,7 +172,9 @@ CREATE TABLE public.collections (
is_trashed boolean DEFAULT false NOT NULL,
storage_classes_desired jsonb DEFAULT '["default"]'::jsonb,
storage_classes_confirmed jsonb DEFAULT '[]'::jsonb,
- storage_classes_confirmed_at timestamp without time zone
+ storage_classes_confirmed_at timestamp without time zone,
+ current_version_uuid character varying,
+ version integer DEFAULT 1 NOT NULL
);
@@ -1782,6 +1784,13 @@ CREATE INDEX index_collections_on_created_at ON public.collections USING btree (
--
+-- Name: index_collections_on_current_version_uuid_and_version; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE UNIQUE INDEX index_collections_on_current_version_uuid_and_version ON public.collections USING btree (current_version_uuid, version);
+
+
+--
-- Name: index_collections_on_delete_at; Type: INDEX; Schema: public; Owner: -
--
@@ -3169,3 +3178,7 @@ INSERT INTO schema_migrations (version) VALUES ('20180824155207');
INSERT INTO schema_migrations (version) VALUES ('20180904110712');
+INSERT INTO schema_migrations (version) VALUES ('20180913175443');
+
+INSERT INTO schema_migrations (version) VALUES ('20180915155335');
+
-----------------------------------------------------------------------
hooks/post-receive
--
More information about the arvados-commits
mailing list