def scan_all(namespace, set_name, bin_names = nil, options = nil)
      policy = create_policy(options, ScanPolicy, default_scan_policy)

      # wait until all migrations are finished
      # TODO: implement
      # @cluster.WaitUntillMigrationIsFinished(policy.timeout)

      # Retry policy must be one-shot for scans.
      # copy on write for policy
      new_policy = policy.clone

      nodes = @cluster.nodes
      if nodes.empty?
        raise Aerospike::Exceptions::Aerospike.new(Aerospike::ResultCode::SERVER_NOT_AVAILABLE, "Scan failed because cluster is empty.")
      end

      recordset = Recordset.new(policy.record_queue_size, nodes.length, :scan)

      if policy.concurrent_nodes
        # Use a thread per node
        nodes.each do |node|
          Thread.new do
            Thread.current.abort_on_exception = true
            command = ScanCommand.new(node, new_policy, namespace, set_name, bin_names, recordset)
            begin
              execute_command(command)
            rescue => e
              Aerospike.logger.error(e.backtrace.join("\n")) unless e == SCAN_TERMINATED_EXCEPTION
              recordset.cancel(e)
            ensure
              recordset.thread_finished
            end
          end
        end
      else
        Thread.new do
          Thread.current.abort_on_exception = true
          nodes.each do |node|
            command = ScanCommand.new(node, new_policy, namespace, set_name, bin_names, recordset)
            begin
              execute_command(command)
            rescue => e
              Aerospike.logger.error(e.backtrace.join("\n")) unless e == SCAN_TERMINATED_EXCEPTION
              recordset.cancel(e)
            ensure
              recordset.thread_finished
            end
          end
        end
      end

      recordset
    end
def scan_all(namespace, set_name, bin_names = nil, options = nil)
      policy = create_policy(options, ScanPolicy, default_scan_policy)

      # wait until all migrations are finished
      # TODO: implement
      # @cluster.WaitUntillMigrationIsFinished(policy.timeout)

      # Retry policy must be one-shot for scans.
      # copy on write for policy
      new_policy = policy.clone

      nodes = @cluster.nodes
      if nodes.empty?
        raise Aerospike::Exceptions::Aerospike.new(Aerospike::ResultCode::SERVER_NOT_AVAILABLE, "Scan failed because cluster is empty.")
      end

      recordset = Recordset.new(policy.record_queue_size, nodes.length, :scan)

      if policy.concurrent_nodes
        # Use a thread per node
        nodes.each do |node|
          Thread.new do
            Thread.current.abort_on_exception = true
            command = ScanCommand.new(node, new_policy, namespace, set_name, bin_names, recordset)
            begin
              execute_command(command)
            rescue => e
              Aerospike.logger.error(e.backtrace.join("\n")) unless e == SCAN_TERMINATED_EXCEPTION
              recordset.cancel(e)
            ensure
              recordset.thread_finished
            end
          end
        end
      else
        Thread.new do
          Thread.current.abort_on_exception = true
          nodes.each do |node|
            command = ScanCommand.new(node, new_policy, namespace, set_name, bin_names, recordset)
            begin
              execute_command(command)
            rescue => e
              Aerospike.logger.error(e.backtrace.join("\n")) unless e == SCAN_TERMINATED_EXCEPTION
              recordset.cancel(e)
            ensure
              recordset.thread_finished
            end
          end
        end
      end

      recordset
    end
-------------------------------------------------------
 Scan Operations
-------------------------------------------------------