Merge branch 'master' into 9998-no-count-items-available
authorTom Clegg <tom@curoverse.com>
Mon, 16 Jan 2017 16:13:32 +0000 (11:13 -0500)
committerTom Clegg <tom@curoverse.com>
Mon, 16 Jan 2017 16:13:32 +0000 (11:13 -0500)
Conflicts:
sdk/go/arvados/resource_list.go
services/keep-balance/collection.go

1  2 
sdk/go/arvados/resource_list.go
services/api/app/controllers/application_controller.rb
services/api/app/controllers/arvados/v1/schema_controller.rb
services/keep-balance/collection.go

index 2864307ebfa029024894b6fe4bdac3667f98fc73,242fb7e406542bda161a528519ea03f4f204db0e..0cc665807b17e4d5a9735c6bf1b7f4242ec08998
@@@ -5,13 -5,12 +5,14 @@@ import "encoding/json
  // ResourceListParams expresses which results are requested in a
  // list/index API.
  type ResourceListParams struct {
-       Select   []string `json:"select,omitempty"`
-       Filters  []Filter `json:"filters,omitempty"`
-       Limit    *int     `json:"limit,omitempty"`
-       Offset   int      `json:"offset,omitempty"`
-       Order    string   `json:"order,omitempty"`
-       Distinct bool     `json:"distinct,omitempty"`
-       Count    bool     `json:"count,omitempty"`
+       Select       []string `json:"select,omitempty"`
+       Filters      []Filter `json:"filters,omitempty"`
+       IncludeTrash bool     `json:"include_trash,omitempty"`
+       Limit        *int     `json:"limit,omitempty"`
+       Offset       int      `json:"offset,omitempty"`
+       Order        string   `json:"order,omitempty"`
++      Distinct     bool     `json:"distinct,omitempty"`
++      Count        bool     `json:"count,omitempty"`
  }
  
  // A Filter restricts the set of records returned by a list/index API.
index 1114ae14dfb5b765d162755261386fe2ed332d92,cdfbdbbcc18b927bbbafe7241697781870fe8e97..3876e673fc80c96d19671248e4b14fbfa247351c
@@@ -19,6 -19,7 +19,7 @@@ class ApplicationController < ActionCon
    include CurrentApiClient
    include ThemesForRails::ActionController
    include LoadParam
+   include DbCurrentTime
  
    respond_to :json
    protect_from_forgery
@@@ -46,7 -47,9 +47,9 @@@
  
    theme :select_theme
  
-   attr_accessor :resource_attrs
+   attr_writer :resource_attrs
+   MAX_UNIQUE_NAME_ATTEMPTS = 10
  
    begin
      rescue_from(Exception,
                  :with => :render_not_found)
    end
  
+   def initialize *args
+     super
+     @object = nil
+     @objects = nil
+     @offset = nil
+     @limit = nil
+     @select = nil
+     @distinct = nil
+     @response_resource_name = nil
+     @attrs = nil
+   end
    def default_url_options
      if Rails.configuration.host
        {:host => Rails.configuration.host}
      if @object.respond_to? :name and params[:ensure_unique_name]
        # Record the original name.  See below.
        name_stem = @object.name
-       counter = 1
+       retries = MAX_UNIQUE_NAME_ATTEMPTS
+     else
+       retries = 0
      end
  
      begin
        @object.save!
      rescue ActiveRecord::RecordNotUnique => rn
-       raise unless params[:ensure_unique_name]
+       raise unless retries > 0
+       retries -= 1
  
        # Dig into the error to determine if it is specifically calling out a
        # (owner_uuid, name) uniqueness violation.  In this specific case, and
        detail = err.result.error_field(PG::Result::PG_DIAG_MESSAGE_DETAIL)
        raise unless /^Key \(owner_uuid, name\)=\([a-z0-9]{5}-[a-z0-9]{5}-[a-z0-9]{15}, .*?\) already exists\./.match detail
  
-       # OK, this exception really is just a unique name constraint
-       # violation, and we've been asked to ensure_unique_name.
-       counter += 1
        @object.uuid = nil
-       @object.name = "#{name_stem} (#{counter})"
-       redo
-     end while false
+       new_name = "#{name_stem} (#{db_current_time.utc.iso8601(3)})"
+       if new_name == @object.name
+         # If the database is fast enough to do two attempts in the
+         # same millisecond, we need to wait to ensure we try a
+         # different timestamp on each attempt.
+         sleep 0.002
+         new_name = "#{name_stem} (#{db_current_time.utc.iso8601(3)})"
+       end
+       @object.name = new_name
+       retry
+     end
      show
    end
  
    end
  
    def find_object_by_uuid
-     if params[:id] and params[:id].match /\D/
+     if params[:id] and params[:id].match(/\D/)
        params[:uuid] = params.delete :id
      end
      @where = { uuid: params[:uuid] }
        :limit => @limit,
        :items => @objects.as_api_response(nil, {select: @select})
      }
 -    if @objects.respond_to? :except
 -      list[:items_available] = @objects.
 -        except(:limit).except(:offset).
 -        count(:id, distinct: true)
 +    if params[:count].nil? || params[:count]
 +      if @objects.respond_to? :except
 +        list[:items_available] = @objects.
 +          except(:limit).except(:offset).
 +          count(:id, distinct: true)
 +      end
      end
      list
    end
        distinct: { type: 'boolean', required: false },
        limit: { type: 'integer', required: false, default: DEFAULT_LIMIT },
        offset: { type: 'integer', required: false, default: 0 },
 +      count: { type: 'boolean', required: false, default: true},
      }
    end
  
          }
        end
      end
-     super *opts
+     super(*opts)
    end
  
    def select_theme
index 3952db61b08d3c458580893f2c6a49ef85df43aa,5f43ba8af8e2c9146af1fc267bd6888748b05510..2eaeb909cf62e44d6ea9822aefda902a2bd0cd09
@@@ -85,7 -85,7 +85,7 @@@ class Arvados::V1::SchemaController < A
        if Rails.application.config.websocket_address
          discovery[:websocketUrl] = Rails.application.config.websocket_address
        elsif ENV['ARVADOS_WEBSOCKETS']
-         discovery[:websocketUrl] = (root_url.sub /^http/, 'ws') + "websocket"
+         discovery[:websocketUrl] = root_url.sub(/^http/, 'ws') + "websocket"
        end
  
        ActiveRecord::Base.descendants.reject(&:abstract_class?).each do |k|
                  },
                  select: {
                    type: "array",
 -                  description: "Select which fields to return",
 +                  description: "Select which fields to return.",
                    location: "query"
                  },
                  distinct: {
                    type: "boolean",
 -                  description: "Return each distinct object",
 +                  description: "Return each distinct object.",
 +                  location: "query"
 +                },
 +                count: {
 +                  type: "boolean",
 +                  description: "Count items_available.",
 +                  default: "true",
                    location: "query"
                  }
                },
                method = d_methods[action.to_sym]
              end
              if ctl_class.respond_to? "_#{action}_requires_parameters".to_sym
-               ctl_class.send("_#{action}_requires_parameters".to_sym).each do |k, v|
+               ctl_class.send("_#{action}_requires_parameters".to_sym).each do |l, v|
                  if v.is_a? Hash
-                   method[:parameters][k] = v
+                   method[:parameters][l] = v
                  else
-                   method[:parameters][k] = {}
+                   method[:parameters][l] = {}
                  end
-                 if !method[:parameters][k][:default].nil?
+                 if !method[:parameters][l][:default].nil?
                    # The JAVA SDK is sensitive to all values being strings
-                   method[:parameters][k][:default] = method[:parameters][k][:default].to_s
+                   method[:parameters][l][:default] = method[:parameters][l][:default].to_s
                  end
-                 method[:parameters][k][:type] ||= 'string'
-                 method[:parameters][k][:description] ||= ''
-                 method[:parameters][k][:location] = (route.segment_keys.include?(k) ? 'path' : 'query')
-                 if method[:parameters][k][:required].nil?
-                   method[:parameters][k][:required] = v != false
+                 method[:parameters][l][:type] ||= 'string'
+                 method[:parameters][l][:description] ||= ''
+                 method[:parameters][l][:location] = (route.segment_keys.include?(l) ? 'path' : 'query')
+                 if method[:parameters][l][:required].nil?
+                   method[:parameters][l][:required] = v != false
                  end
                end
              end
index 060621b7715b55efd450d1753c57b296ef5d33fb,b3a631e979a77a78f6c7a8b60fd012e77b360368..15556ed61282ad551fd171af4efce2813dc69f04
@@@ -11,7 -11,6 +11,7 @@@ func countCollections(c *arvados.Client
        var page arvados.CollectionList
        var zero int
        params.Limit = &zero
 +      params.Count = true
        err := c.RequestAndDecode(&page, "GET", "arvados/v1/collections", nil, params)
        return page.ItemsAvailable, err
  }
@@@ -31,7 -30,9 +31,9 @@@ func EachCollection(c *arvados.Client, 
                progress = func(_, _ int) {}
        }
  
-       expectCount, err := countCollections(c, arvados.ResourceListParams{})
+       expectCount, err := countCollections(c, arvados.ResourceListParams{
+               IncludeTrash: true,
+       })
        if err != nil {
                return err
        }
                limit = 1<<31 - 1
        }
        params := arvados.ResourceListParams{
-               Limit:  &limit,
-               Order:  "modified_at, uuid",
-               Count:  false,
-               Select: []string{"uuid", "manifest_text", "modified_at", "portable_data_hash", "replication_desired"},
+               Limit:        &limit,
+               Order:        "modified_at, uuid",
++              Count:        false,
+               Select:       []string{"uuid", "unsigned_manifest_text", "modified_at", "portable_data_hash", "replication_desired"},
+               IncludeTrash: true,
        }
        var last arvados.Collection
        var filterTime time.Time
        }
        progress(callCount, expectCount)
  
-       if checkCount, err := countCollections(c, arvados.ResourceListParams{Filters: []arvados.Filter{{
-               Attr:     "modified_at",
-               Operator: "<=",
-               Operand:  filterTime}}}); err != nil {
+       if checkCount, err := countCollections(c, arvados.ResourceListParams{
+               Filters: []arvados.Filter{{
+                       Attr:     "modified_at",
+                       Operator: "<=",
+                       Operand:  filterTime}},
+               IncludeTrash: true,
+       }); err != nil {
                return err
        } else if callCount < checkCount {
                return fmt.Errorf("Retrieved %d collections with modtime <= T=%q, but server now reports there are %d collections with modtime <= T", callCount, filterTime, checkCount)