public static void ScanNodes(Cluster cluster, ScanPolicy policy, string ns, string setName, string[] binNames, ScanCallback callback, Node[] nodes)
        {
            policy.Validate();

            // Detect cluster migrations when performing scan.
            ulong taskId     = RandomShift.ThreadLocalInstance.NextLong();
            ulong clusterKey = policy.failOnClusterChange ? QueryValidate.ValidateBegin(nodes[0], ns) : 0;
            bool  first      = true;

            if (policy.concurrentNodes && nodes.Length > 1)
            {
                Executor executor = new Executor(nodes.Length);

                foreach (Node node in nodes)
                {
                    ScanCommand command = new ScanCommand(cluster, node, policy, ns, setName, binNames, callback, taskId, clusterKey, first);
                    executor.AddCommand(command);
                    first = false;
                }
                executor.Execute(policy.maxConcurrentNodes);
            }
            else
            {
                foreach (Node node in nodes)
                {
                    ScanCommand command = new ScanCommand(cluster, node, policy, ns, setName, binNames, callback, taskId, clusterKey, first);
                    command.Execute();
                    first = false;
                }
            }
        }
        //-------------------------------------------------------
        // Scan Operations
        //-------------------------------------------------------
        /// <summary>
        /// Read all records in specified namespace and set.  If the policy's 
        /// concurrentNodes is specified, each server node will be read in
        /// parallel.  Otherwise, server nodes are read in series.
        /// <para>
        /// This call will block until the scan is complete - callbacks are made
        /// within the scope of this call.
        /// </para>
        /// </summary>
        /// <param name="policy">scan configuration parameters, pass in null for defaults</param>
        /// <param name="ns">namespace - equivalent to database name</param>
        /// <param name="setName">optional set name - equivalent to database table</param>
        /// <param name="callback">read callback method - called with record data</param>
        /// <param name="binNames">
        /// optional bin to retrieve. All bins will be returned if not specified.
        /// Aerospike 2 servers ignore this parameter.
        /// </param>
        /// <exception cref="AerospikeException">if scan fails</exception>
        public void ScanAll(ScanPolicy policy, string ns, string setName, ScanCallback callback, params string[] binNames)
        {
            if (policy == null)
            {
                policy = scanPolicyDefault;
            }

            Node[] nodes = cluster.Nodes;

            if (nodes.Length == 0)
            {
                throw new AerospikeException(ResultCode.SERVER_NOT_AVAILABLE, "Scan failed because cluster is empty.");
            }

            if (policy.concurrentNodes)
            {
                Executor executor = new Executor(nodes.Length);
                ulong taskId = RandomShift.ThreadLocalInstance.NextLong();

                foreach (Node node in nodes)
                {
                    ScanCommand command = new ScanCommand(node, policy, ns, setName, callback, binNames, taskId);
                    executor.AddCommand(command);
                }

                executor.Execute(policy.maxConcurrentNodes);
            }
            else
            {
                foreach (Node node in nodes)
                {
                    ScanNode(policy, node, ns, setName, callback, binNames);
                }
            }
        }
        /// <summary>
        /// Read all records in specified namespace and set for one node only.
        /// <para>
        /// This call will block until the scan is complete - callbacks are made
        /// within the scope of this call.
        /// </para>
        /// </summary>
        /// <param name="policy">scan configuration parameters, pass in null for defaults</param>
        /// <param name="node">server node</param>
        /// <param name="ns">namespace - equivalent to database name</param>
        /// <param name="setName">optional set name - equivalent to database table</param>
        /// <param name="callback">read callback method - called with record data</param>
        /// <param name="binNames">
        /// optional bin to retrieve. All bins will be returned if not specified.
        /// Aerospike 2 servers ignore this parameter.
        /// </param>
        /// <exception cref="AerospikeException">if transaction fails</exception>
        public void ScanNode(ScanPolicy policy, Node node, string ns, string setName, ScanCallback callback, params string[] binNames)
        {
            if (policy == null)
            {
                policy = scanPolicyDefault;
            }
            ulong taskId = RandomShift.ThreadLocalInstance.NextLong();

            ScanCommand command = new ScanCommand(node, policy, ns, setName, callback, binNames, taskId);
            command.Execute();
        }
        /// <summary>
        /// Read all records in specified namespace and set for one node only.
        /// <para>
        /// This call will block until the scan is complete - callbacks are made
        /// within the scope of this call.
        /// </para>
        /// </summary>
        /// <param name="policy">scan configuration parameters, pass in null for defaults</param>
        /// <param name="node">server node</param>
        /// <param name="ns">namespace - equivalent to database name</param>
        /// <param name="setName">optional set name - equivalent to database table</param>
        /// <param name="callback">read callback method - called with record data</param>
        /// <param name="binNames">
        /// optional bin to retrieve. All bins will be returned if not specified.
        /// Aerospike 2 servers ignore this parameter.
        /// </param>
        /// <exception cref="AerospikeException">if transaction fails</exception>
        public void ScanNode(ScanPolicy policy, Node node, string ns, string setName, ScanCallback callback, params string[] binNames)
        {
            if (policy == null)
            {
                policy = scanPolicyDefault;
            }
            long taskId = Environment.TickCount;

            ScanCommand command = new ScanCommand(node, policy, ns, setName, callback, binNames, taskId);
            command.Execute();
        }