Exemple #1
0
 public BatchCommand(Executor parent, BatchNode batch, BatchPolicy policy)
     : base(batch.node, false)
 {
     this.parent = parent;
     this.batch  = batch;
     this.policy = policy;
 }
 public AsyncBatchCommand(AsyncBatchExecutor parent, AsyncCluster cluster, BatchNode batch, BatchPolicy batchPolicy)
     : base(parent, cluster, batchPolicy, (AsyncNode)batch.node)
 {
     this.parent      = parent;
     this.batch       = batch;
     this.batchPolicy = batchPolicy;
 }
        public static void Main(string[] args)
        {
            var client = Connect();
            var policy = new Policy();
            var writePolicy = new WritePolicy();
            var batchPolicy = new BatchPolicy();

            //NOTE: adjust the timeout value depending on your demo machine
            writePolicy.timeout = 1000;
            var key = new Key("test", "myset", "mykey");

            WriteSingleValue(client, writePolicy, key);
            CheckKeyExists(client, policy, key);
            AddSingleValue(client, writePolicy);
            WriteMultipleValues(client, writePolicy, key);
            WriteValueWithTtl(client);

            ReadAllValuesForKey(client, policy, key);
            ReadSomeValuesForKey(client, policy, key);

            DeleteValue(client, writePolicy, key);
            DeleteRecord(client, writePolicy, key);

            AddRecords(client, writePolicy);
            BatchReadRecords(client, batchPolicy);

            MultiOps(client, writePolicy, key);

            client.Close();
        }
        public AsyncBatchExistsArrayExecutor
        (
            AsyncCluster cluster,
            BatchPolicy policy,
            Key[] keys,
            ExistsArrayListener listener
        )
        {
            this.keys        = keys;
            this.existsArray = new bool[keys.Length];
            this.listener    = listener;

            // Create commands.
            List <BatchNode> batchNodes = BatchNode.GenerateList(cluster, policy, keys);

            AsyncBatchCommand[] commands = new AsyncBatchCommand[batchNodes.Count];
            int count = 0;

            foreach (BatchNode batchNode in batchNodes)
            {
                commands[count++] = new AsyncBatchExistsArrayCommand(this, cluster, batchNode, policy, keys, existsArray);
            }
            // Dispatch commands to nodes.
            Execute(commands);
        }
        public AsyncBatchReadListExecutor
        (
            AsyncCluster cluster,
            BatchPolicy policy,
            BatchListListener listener,
            List <BatchRead> records
        )
        {
            this.listener = listener;
            this.records  = records;

            // Create commands.
            List <BatchNode> batchNodes = BatchNode.GenerateList(cluster, policy, records);

            AsyncMultiCommand[] tasks = new AsyncMultiCommand[batchNodes.Count];
            int count = 0;

            foreach (BatchNode batchNode in batchNodes)
            {
                if (!batchNode.node.hasBatchIndex)
                {
                    throw new AerospikeException(ResultCode.PARAMETER_ERROR, "Requested command requires a server that supports new batch index protocol.");
                }
                tasks[count++] = new AsyncBatchReadListCommand(this, cluster, batchNode, policy, records);
            }
            // Dispatch commands to nodes.
            Execute(tasks, policy.maxConcurrentThreads);
        }
Exemple #6
0
 public AsyncBatchExistsArrayCommand(AsyncBatchExistsArrayCommand other) : base(other)
 {
     this.batch       = other.batch;
     this.batchPolicy = other.batchPolicy;
     this.keys        = other.keys;
     this.existsArray = other.existsArray;
 }
 public BatchCommand(Cluster cluster, Executor parent, BatchNode batch, BatchPolicy batchPolicy)
     : base(cluster, batchPolicy, batch.node, false)
 {
     this.parent      = parent;
     this.batch       = batch;
     this.batchPolicy = batchPolicy;
 }
        public AsyncBatchExistsSequenceExecutor
        (
            AsyncCluster cluster,
            BatchPolicy policy,
            Key[] keys,
            ExistsSequenceListener listener
        ) : base(cluster, policy, keys)
        {
            this.listener = listener;

            // Create commands.
            AsyncMultiCommand[] tasks = new AsyncMultiCommand[base.taskSize];
            int count = 0;

            foreach (BatchNode batchNode in batchNodes)
            {
                if (batchNode.node.UseNewBatch(policy))
                {
                    // New batch
                    tasks[count++] = new AsyncBatchExistsSequenceCommand(this, cluster, batchNode, policy, keys, listener);
                }
                else
                {
                    // Old batch only allows one namespace per call.
                    foreach (BatchNode.BatchNamespace batchNamespace in batchNode.batchNamespaces)
                    {
                        tasks[count++] = new AsyncBatchExistsSequenceDirect(this, cluster, (AsyncNode)batchNode.node, batchNamespace, policy, keys, listener);
                    }
                }
            }
            // Dispatch commands to nodes.
            Execute(tasks, policy.maxConcurrentThreads);
        }
        public AsyncBatchGetSequenceExecutor
        (
            AsyncCluster cluster,
            BatchPolicy policy,
            RecordSequenceListener listener,
            Key[] keys,
            string[] binNames,
            int readAttr
        )
        {
            this.listener = listener;

            // Create commands.
            List <BatchNode> batchNodes = BatchNode.GenerateList(cluster, policy, keys);

            AsyncBatchCommand[] commands = new AsyncBatchCommand[batchNodes.Count];
            int count = 0;

            foreach (BatchNode batchNode in batchNodes)
            {
                commands[count++] = new AsyncBatchGetSequenceCommand(this, cluster, batchNode, policy, keys, binNames, listener, readAttr);
            }
            // Dispatch commands to nodes.
            Execute(commands);
        }
Exemple #10
0
        public static List <BatchNode> GenerateList(Cluster cluster, BatchPolicy policy, Key[] keys)
        {
            Node[] nodes = cluster.Nodes;

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

            int nodeCount   = nodes.Length;
            int keysPerNode = keys.Length / nodeCount + 10;

            // Split keys by server node.
            List <BatchNode> batchNodes = new List <BatchNode>(nodeCount + 1);

            for (int i = 0; i < keys.Length; i++)
            {
                Key       key       = keys[i];
                Partition partition = new Partition(key);
                BatchNode batchNode;

                Node node = cluster.GetReadNode(partition, policy.replica);
                batchNode = FindBatchNode(batchNodes, node);

                if (batchNode == null)
                {
                    batchNodes.Add(new BatchNode(node, keysPerNode, key.ns, i));
                }
                else
                {
                    batchNode.AddKey(key.ns, i);
                }
            }
            return(batchNodes);
        }
 /// <summary>
 /// Copy client policy from another client policy.
 /// </summary>
 public ClientPolicy(ClientPolicy other)
 {
     this.user                 = other.user;
     this.password             = other.password;
     this.clusterName          = other.clusterName;
     this.authMode             = other.authMode;
     this.timeout              = other.timeout;
     this.loginTimeout         = other.loginTimeout;
     this.maxConnsPerNode      = other.maxConnsPerNode;
     this.connPoolsPerNode     = other.connPoolsPerNode;
     this.maxSocketIdle        = other.maxSocketIdle;
     this.tendInterval         = other.tendInterval;
     this.failIfNotConnected   = other.failIfNotConnected;
     this.readPolicyDefault    = new Policy(other.readPolicyDefault);
     this.writePolicyDefault   = new WritePolicy(other.writePolicyDefault);
     this.scanPolicyDefault    = new ScanPolicy(other.scanPolicyDefault);
     this.queryPolicyDefault   = new QueryPolicy(other.queryPolicyDefault);
     this.batchPolicyDefault   = new BatchPolicy(other.batchPolicyDefault);
     this.infoPolicyDefault    = new InfoPolicy(other.infoPolicyDefault);
     this.tlsPolicy            = (other.tlsPolicy != null) ? new TlsPolicy(other.tlsPolicy) : null;
     this.ipMap                = other.ipMap;
     this.useServicesAlternate = other.useServicesAlternate;
     this.rackAware            = other.rackAware;
     this.rackId               = other.rackId;
 }
Exemple #12
0
 public AsyncBatchExistsSequenceCommand(AsyncBatchExistsSequenceCommand other) : base(other)
 {
     this.batch       = other.batch;
     this.batchPolicy = other.batchPolicy;
     this.keys        = other.keys;
     this.listener    = other.listener;
 }
 public BatchReadListCommand(BatchNode batch, BatchPolicy policy, List <BatchRead> records)
     : base(batch.node, false)
 {
     this.batch   = batch;
     this.policy  = policy;
     this.records = records;
 }
 public AsyncBatchCommand(AsyncBatchCommand other) : base(other)
 {
     this.batch       = other.batch;
     this.batchPolicy = other.batchPolicy;
     this.sequenceAP  = other.sequenceAP;
     this.sequenceSC  = other.sequenceSC;
 }
        public AsyncBatchExistsArrayExecutor(
			AsyncCluster cluster,
			BatchPolicy policy,
			Key[] keys,
			ExistsArrayListener listener
		)
            : base(cluster, policy, keys)
        {
            this.existsArray = new bool[keys.Length];
            this.listener = listener;

            // Create commands.
            AsyncMultiCommand[] tasks = new AsyncMultiCommand[base.taskSize];
            int count = 0;

            foreach (BatchNode batchNode in batchNodes)
            {
                if (batchNode.node.UseNewBatch(policy))
                {
                    // New batch
                    tasks[count++] = new AsyncBatchExistsArrayCommand(this, cluster, batchNode, policy, keys, existsArray);
                }
                else
                {
                    // Old batch only allows one namespace per call.
                    foreach (BatchNode.BatchNamespace batchNamespace in batchNode.batchNamespaces)
                    {
                        tasks[count++] = new AsyncBatchExistsArrayDirect(this, cluster, (AsyncNode)batchNode.node, batchNamespace, policy, keys, existsArray);
                    }
                }
            }
            // Dispatch commands to nodes.
            Execute(tasks, policy.maxConcurrentThreads);
        }
 public AsyncBatchExecutor(AsyncCluster cluster, BatchPolicy policy, Key[] keys, bool stopOnFailure)
     : base(cluster, stopOnFailure)
 {
     this.keys       = keys;
     this.batchNodes = BatchNode.GenerateList(cluster, policy, keys);
     this.taskSize   = batchNodes.Count;
 }
Exemple #17
0
 public AsyncBatchReadSequenceCommand(AsyncBatchReadSequenceCommand other) : base(other)
 {
     this.batch       = other.batch;
     this.batchPolicy = other.batchPolicy;
     this.listener    = other.listener;
     this.records     = other.records;
 }
Exemple #18
0
        public AsyncBatchExistsArrayExecutor
        (
            AsyncCluster cluster,
            BatchPolicy policy,
            Key[] keys,
            ExistsArrayListener listener
        ) : base(cluster, policy, keys)
        {
            this.existsArray = new bool[keys.Length];
            this.listener    = listener;

            // Create commands.
            AsyncMultiCommand[] tasks = new AsyncMultiCommand[base.taskSize];
            int count = 0;

            foreach (BatchNode batchNode in batchNodes)
            {
                if (batchNode.node.UseNewBatch(policy))
                {
                    // New batch
                    tasks[count++] = new AsyncBatchExistsArrayCommand(this, cluster, batchNode, policy, keys, existsArray);
                }
                else
                {
                    // Old batch only allows one namespace per call.
                    foreach (BatchNode.BatchNamespace batchNamespace in batchNode.batchNamespaces)
                    {
                        tasks[count++] = new AsyncBatchExistsArrayDirect(this, cluster, (AsyncNode)batchNode.node, batchNamespace, policy, keys, existsArray);
                    }
                }
            }
            // Dispatch commands to nodes.
            Execute(tasks, 0);
        }
Exemple #19
0
 public BatchReadListCommand(Executor parent, BatchNode batch, BatchPolicy policy, List <BatchRead> records)
     : base(false)
 {
     this.parent  = parent;
     this.batch   = batch;
     this.policy  = policy;
     this.records = records;
 }
Exemple #20
0
 public AsyncBatchGetSequenceCommand(AsyncBatchGetSequenceCommand other) : base(other)
 {
     this.batch       = other.batch;
     this.batchPolicy = other.batchPolicy;
     this.keys        = other.keys;
     this.binNames    = other.binNames;
     this.listener    = other.listener;
     this.readAttr    = other.readAttr;
 }
Exemple #21
0
 public AsyncBatchGetArrayCommand(AsyncBatchGetArrayCommand other) : base(other)
 {
     this.batch       = other.batch;
     this.batchPolicy = other.batchPolicy;
     this.keys        = other.keys;
     this.binNames    = other.binNames;
     this.records     = other.records;
     this.readAttr    = other.readAttr;
 }
 public AsyncBatchReadListCommand
 (
     AsyncMultiExecutor parent,
     AsyncCluster cluster,
     BatchNode batch,
     BatchPolicy batchPolicy,
     List <BatchRead> records
 ) : base(parent, cluster, batch, batchPolicy)
 {
     this.records = records;
 }
 public BatchReadListCommand
 (
     Cluster cluster,
     Executor parent,
     BatchNode batch,
     BatchPolicy policy,
     List <BatchRead> records
 ) : base(cluster, parent, batch, policy)
 {
     this.records = records;
 }
 private static void BatchReadRecords(AerospikeClient client, BatchPolicy batchPolicy)
 {
     Console.WriteLine("Batch Reads");
     const int size = 1024;
     var keys = new Key[size];
     for (var i = 0; i < keys.Length; i++)
     {
         keys[i] = new Key("test", "myset", (i + 1));
     }
     var records = client.Get(batchPolicy, keys);
     Console.WriteLine("Read " + records.Length + " records");
 }
Exemple #25
0
 public BatchExistsArrayCommand
 (
     Executor parent,
     BatchNode batch,
     BatchPolicy policy,
     Key[] keys,
     bool[] existsArray
 ) : base(parent, batch, policy)
 {
     this.keys        = keys;
     this.existsArray = existsArray;
 }
        public static List <BatchNode> GenerateList
        (
            Cluster cluster,
            BatchPolicy policy,
            Key[] keys,
            uint sequenceAP,
            uint sequenceSC,
            BatchNode batchSeed
        )
        {
            Node[] nodes = cluster.Nodes;

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

            // Create initial key capacity for each node as average + 25%.
            int keysPerNode = batchSeed.offsetsSize / nodes.Length;

            keysPerNode += (int)((uint)keysPerNode >> 2);

            // The minimum key capacity is 10.
            if (keysPerNode < 10)
            {
                keysPerNode = 10;
            }

            Replica replica   = policy.replica;
            Replica replicaSC = Partition.GetReplicaSC(policy);

            // Split keys by server node.
            List <BatchNode> batchNodes = new List <BatchNode>(nodes.Length);

            for (int i = 0; i < batchSeed.offsetsSize; i++)
            {
                int offset = batchSeed.offsets[i];

                Node      node      = Partition.GetNodeBatchRead(cluster, keys[offset], replica, replicaSC, sequenceAP, sequenceSC);
                BatchNode batchNode = FindBatchNode(batchNodes, node);

                if (batchNode == null)
                {
                    batchNodes.Add(new BatchNode(node, keysPerNode, offset));
                }
                else
                {
                    batchNode.AddKey(offset);
                }
            }
            return(batchNodes);
        }
 public AsyncBatchExistsSequenceCommand
 (
     AsyncMultiExecutor parent,
     AsyncCluster cluster,
     BatchNode batch,
     BatchPolicy batchPolicy,
     Key[] keys,
     ExistsSequenceListener listener
 ) : base(parent, cluster, batch, batchPolicy)
 {
     this.keys     = keys;
     this.listener = listener;
 }
 public AsyncBatchExistsArrayCommand
 (
     AsyncMultiExecutor parent,
     AsyncCluster cluster,
     BatchNode batch,
     BatchPolicy batchPolicy,
     Key[] keys,
     bool[] existsArray
 ) : base(parent, cluster, batch, batchPolicy)
 {
     this.keys        = keys;
     this.existsArray = existsArray;
 }
 public AsyncBatchReadSequenceCommand
 (
     AsyncMultiExecutor parent,
     AsyncCluster cluster,
     BatchNode batch,
     BatchPolicy batchPolicy,
     BatchSequenceListener listener,
     List <BatchRead> records
 ) : base(parent, cluster, batch, batchPolicy)
 {
     this.listener = listener;
     this.records  = records;
 }
        public BatchExistsArrayCommand(
			BatchNode batch,
			BatchPolicy policy,
			Key[] keys,
			bool[] existsArray
		)
            : base(batch.node, false)
        {
            this.batch = batch;
            this.policy = policy;
            this.keys = keys;
            this.existsArray = existsArray;
        }
 private static void ExecuteNode(Cluster cluster, BatchNode batchNode, BatchPolicy policy, Key[] keys, bool[] existsArray, Record[] records, string[] binNames, int readAttr)
 {
     if (records != null)
     {
         MultiCommand command = new BatchGetArrayCommand(cluster, null, batchNode, policy, keys, binNames, records, readAttr);
         command.Execute();
     }
     else
     {
         MultiCommand command = new BatchExistsArrayCommand(cluster, null, batchNode, policy, keys, existsArray);
         command.Execute();
     }
 }
 public BatchExistsArrayCommand
 (
     BatchNode batch,
     BatchPolicy policy,
     Key[] keys,
     bool[] existsArray
 ) : base(batch.node, false)
 {
     this.batch       = batch;
     this.policy      = policy;
     this.keys        = keys;
     this.existsArray = existsArray;
 }
 public AsyncBatchReadListCommand
 (
     AsyncMultiExecutor parent,
     AsyncCluster cluster,
     BatchNode batch,
     BatchPolicy policy,
     List <BatchRead> records
 ) : base(parent, cluster, (AsyncNode)batch.node, false)
 {
     this.batch   = batch;
     this.policy  = policy;
     this.records = records;
 }
        public AsyncBatchExecutor(Cluster cluster, BatchPolicy policy, Key[] keys)
        {
            this.keys       = keys;
            this.batchNodes = BatchNode.GenerateList(cluster, policy, keys);

            // Count number of asynchronous commands needed.
            int size = 0;

            foreach (BatchNode batchNode in batchNodes)
            {
                size += batchNode.batchNamespaces.Count;
            }
            completedSize = size;
        }
        public static List<BatchNode> GenerateList(Cluster cluster, BatchPolicy policy, Key[] keys)
        {
            Node[] nodes = cluster.Nodes;

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

            // Create initial key capacity for each node as average + 25%.
            int keysPerNode = keys.Length / nodes.Length;
            keysPerNode += (int)((uint)keysPerNode >> 2);

            // The minimum key capacity is 10.
            if (keysPerNode < 10)
            {
                keysPerNode = 10;
            }

            // Split keys by server node.
            List<BatchNode> batchNodes = new List<BatchNode>(nodes.Length);

            for (int i = 0; i < keys.Length; i++)
            {
                Partition partition = new Partition(keys[i]);
                Node node = cluster.GetReadNode(partition, policy.replica);
                BatchNode batchNode = FindBatchNode(batchNodes, node);

                if (batchNode == null)
                {
                    batchNodes.Add(new BatchNode(node, keysPerNode, i));
                }
                else
                {
                    batchNode.AddKey(i);
                }
            }
            return batchNodes;
        }
        /// <summary>
        /// Initialize large stack operator.
        /// </summary>
        /// <param name="client">client</param>
        /// <param name="policy">generic configuration parameters, pass in null for defaults</param>
        /// <param name="key">unique record identifier</param>
        /// <param name="binName">bin name</param>
        /// <param name="headBinName">Bin name for the head counter, null for default</param>
        public LargeStack(AerospikeClient client, WritePolicy policy, Key key, string binName, string headBinName)
        {
            this.client = client;
            this.policy = policy;
            this.key = key;
            this.lockKey = new Key(this.key.ns, LOCK_SET_NAME, this.key.digest);
            this.binName = binName;
            if (headBinName == null)
                this.headBinName = DEFAULT_HEAD_BIN_NAME;
            else
                this.headBinName = headBinName;

            if (this.policy == null){
                this.lockPolicy = new WritePolicy();
            } else {
                this.lockPolicy = new WritePolicy(this.policy);
            }
            if (this.policy != null)
                this.batchPolicy = new BatchPolicy(policy);
            else
                this.batchPolicy = new BatchPolicy(this.client.batchPolicyDefault);
        }
        public AsyncBatchExecutor(Cluster cluster, BatchPolicy policy, Key[] keys)
        {
            this.keys = keys;
            this.batchNodes = BatchNode.GenerateList(cluster, policy, keys);

            // Count number of asynchronous commands needed.
            int size = 0;
            foreach (BatchNode batchNode in batchNodes)
            {
                if (batchNode.node.UseNewBatch(policy))
                {
                    // New batch
                    size++;
                }
                else
                {
                    // Old batch only allows one namespace per call.
                    batchNode.SplitByNamespace(keys);
                    size += batchNode.batchNamespaces.Count;
                }
            }
            this.taskSize = size;
        }
        public static void Execute(Cluster cluster, BatchPolicy policy, Key[] keys, bool[] existsArray, Record[] records, string[] binNames, int readAttr)
        {
            if (keys.Length == 0)
            {
                return;
            }

            if (policy.allowProleReads)
            {
                // Send all requests to a single node chosen in round-robin fashion in this transaction thread.
                Node node = cluster.GetRandomNode();
                BatchNode batchNode = new BatchNode(node, keys);
                ExecuteNode(batchNode, policy, keys, existsArray, records, binNames, readAttr);
                return;
            }

            List<BatchNode> batchNodes = BatchNode.GenerateList(cluster, policy, keys);

            if (policy.maxConcurrentThreads == 1 || batchNodes.Count <= 1)
            {
                // Run batch requests sequentially in same thread.
                foreach (BatchNode batchNode in batchNodes)
                {
                    ExecuteNode(batchNode, policy, keys, existsArray, records, binNames, readAttr);
                }
            }
            else
            {
                // Run batch requests in parallel in separate threads.
                //
                // Multiple threads write to the record/exists array, so one might think that
                // volatile or memory barriers are needed on the write threads and this read thread.
                // This should not be necessary here because it happens in Executor which does a
                // volatile write (Interlocked.Increment(ref completedCount)) at the end of write threads
                // and a synchronized WaitTillComplete() in this thread.
                Executor executor = new Executor(batchNodes.Count * 2);

                // Initialize threads.
                foreach (BatchNode batchNode in batchNodes)
                {
                    if (batchNode.node.UseNewBatch(policy))
                    {
                        // New batch
                        if (records != null)
                        {
                            MultiCommand command = new BatchGetArrayCommand(batchNode, policy, keys, binNames, records, readAttr);
                            executor.AddCommand(command);
                        }
                        else
                        {
                            MultiCommand command = new BatchExistsArrayCommand(batchNode, policy, keys, existsArray);
                            executor.AddCommand(command);
                        }
                    }
                    else
                    {
                        // There may be multiple threads for a single node because the
                        // wire protocol only allows one namespace per command.  Multiple namespaces
                        // require multiple threads per node.
                        batchNode.SplitByNamespace(keys);

                        foreach (BatchNode.BatchNamespace batchNamespace in batchNode.batchNamespaces)
                        {
                            if (records != null)
                            {
                                MultiCommand command = new BatchGetArrayDirect(batchNode.node, batchNamespace, policy, keys, binNames, records, readAttr);
                                executor.AddCommand(command);
                            }
                            else
                            {
                                MultiCommand command = new BatchExistsArrayDirect(batchNode.node, batchNamespace, policy, keys, existsArray);
                                executor.AddCommand(command);
                            }
                        }
                    }
                }
                executor.Execute(policy.maxConcurrentThreads);
            }
        }
        private static void ExecuteNode(BatchNode batchNode, BatchPolicy policy, Key[] keys, bool[] existsArray, Record[] records, string[] binNames, int readAttr)
        {
            if (batchNode.node.UseNewBatch(policy))
            {
                // New batch
                if (records != null)
                {
                    MultiCommand command = new BatchGetArrayCommand(batchNode, policy, keys, binNames, records, readAttr);
                    command.Execute();
                }
                else
                {
                    MultiCommand command = new BatchExistsArrayCommand(batchNode, policy, keys, existsArray);
                    command.Execute();
                }
            }
            else
            {
                // Old batch only allows one namespace per call.
                batchNode.SplitByNamespace(keys);

                foreach (BatchNode.BatchNamespace batchNamespace in batchNode.batchNamespaces)
                {
                    if (records != null)
                    {
                        MultiCommand command = new BatchGetArrayDirect(batchNode.node, batchNamespace, policy, keys, binNames, records, readAttr);
                        command.Execute();
                    }
                    else
                    {
                        MultiCommand command = new BatchExistsArrayDirect(batchNode.node, batchNamespace, policy, keys, existsArray);
                        command.Execute();
                    }
                }
            }
        }
 /// <summary>
 /// Asynchronously read multiple records for specified batch keys in one batch call.
 /// This method allows different namespaces/bins to be requested for each key in the batch.
 /// The returned records are located in the same list.
 /// If the BatchRecord key field is not found, the corresponding record field will be null.
 /// <para>
 /// This method schedules the get command with a channel selector and returns.
 /// Another thread will process the command and send the results to the listener in a single call.
 /// This method requires Aerospike Server version >= 3.6.0.
 /// </para>
 /// </summary>
 /// <param name="policy">batch configuration parameters, pass in null for defaults</param>
 /// <param name="listener">where to send results</param>
 /// <param name="records">list of unique record identifiers and the bins to retrieve.</param>
 /// <exception cref="AerospikeException">if read fails</exception>
 public void Get(BatchPolicy policy, BatchSequenceListener listener, List<BatchRead> records)
 {
     if (records.Count == 0)
     {
         listener.OnSuccess();
         return;
     }
     if (policy == null)
     {
         policy = batchPolicyDefault;
     }
     new AsyncBatchReadSequenceExecutor(cluster, policy, listener, records);
 }
 /// <summary>
 /// Asynchronously check if multiple record keys exist in one batch call.
 /// Create listener, call asynchronous array exists and return task monitor.
 /// <para>
 /// The policy can be used to specify timeouts.
 /// </para>
 /// </summary>
 /// <param name="policy">generic configuration parameters, pass in null for defaults</param>
 /// <param name="token">cancellation token</param>
 /// <param name="keys">array of unique record identifiers</param>
 /// <exception cref="AerospikeException">if queue is full</exception>
 public Task<bool[]> Exists(BatchPolicy policy, CancellationToken token, Key[] keys)
 {
     ExistsArrayListenerAdapter listener = new ExistsArrayListenerAdapter(token);
     Exists(policy, listener, keys);
     return listener.Task;
 }
        public AsyncBatchGetArrayCommand(
			AsyncMultiExecutor parent,
			AsyncCluster cluster,
			BatchNode batch,
			BatchPolicy policy,
			Key[] keys,
			string[] binNames,
			Record[] records,
			int readAttr
		)
            : base(parent, cluster, (AsyncNode)batch.node, false)
        {
            this.batch = batch;
            this.policy = policy;
            this.keys = keys;
            this.binNames = binNames;
            this.records = records;
            this.readAttr = readAttr;
        }
        public AsyncBatchExistsArrayCommand(
			AsyncMultiExecutor parent,
			AsyncCluster cluster,
			BatchNode batch,
			BatchPolicy policy,
			Key[] keys,
			bool[] existsArray
		)
            : base(parent, cluster, (AsyncNode)batch.node, false)
        {
            this.batch = batch;
            this.policy = policy;
            this.keys = keys;
            this.existsArray = existsArray;
        }
 /// <summary>
 /// Use new batch protocol if server supports it and useBatchDirect is not set.
 /// </summary>
 public bool UseNewBatch(BatchPolicy policy)
 {
     return !policy.useBatchDirect && hasBatchIndex;
 }
        public void SetBatchRead(BatchPolicy policy, List<BatchRead> records, BatchNode batch)
        {
            // Estimate full row size
            int[] offsets = batch.offsets;
            int max = batch.offsetsSize;
            BatchRead prev = null;

            Begin();
            dataOffset += FIELD_HEADER_SIZE + 5;

            for (int i = 0; i < max; i++)
            {
                BatchRead record = records[offsets[i]];
                Key key = record.key;
                string[] binNames = record.binNames;

                dataOffset += key.digest.Length + 4;

                // Avoid relatively expensive full equality checks for performance reasons.
                // Use reference equality only in hope that common namespaces/bin names are set from
                // fixed variables.  It's fine if equality not determined correctly because it just
                // results in more space used. The batch will still be correct.
                if (prev != null && prev.key.ns == key.ns && prev.binNames == binNames && prev.readAllBins == record.readAllBins)
                {
                    // Can set repeat previous namespace/bin names to save space.
                    dataOffset++;
                }
                else
                {
                    // Estimate full header, namespace and bin names.
                    dataOffset += ByteUtil.EstimateSizeUtf8(key.ns) + FIELD_HEADER_SIZE + 6;

                    if (binNames != null)
                    {
                        foreach (string binName in binNames)
                        {
                            EstimateOperationSize(binName);
                        }
                    }
                    prev = record;
                }
            }
            SizeBuffer();

            WriteHeader(policy, Command.INFO1_READ | Command.INFO1_BATCH, 0, 1, 0);
            int fieldSizeOffset = dataOffset;
            WriteFieldHeader(0, FieldType.BATCH_INDEX); // Need to update size at end

            ByteUtil.IntToBytes((uint)max, dataBuffer, dataOffset);
            dataOffset += 4;
            dataBuffer[dataOffset++] = (policy.allowInline) ? (byte)1 : (byte)0;
            prev = null;

            for (int i = 0; i < max; i++)
            {
                int index = offsets[i];
                ByteUtil.IntToBytes((uint)index, dataBuffer, dataOffset);
                dataOffset += 4;

                BatchRead record = records[index];
                Key key = record.key;
                string[] binNames = record.binNames;
                byte[] digest = key.digest;
                Array.Copy(digest, 0, dataBuffer, dataOffset, digest.Length);
                dataOffset += digest.Length;

                // Avoid relatively expensive full equality checks for performance reasons.
                // Use reference equality only in hope that common namespaces/bin names are set from
                // fixed variables.  It's fine if equality not determined correctly because it just
                // results in more space used. The batch will still be correct.
                if (prev != null && prev.key.ns == key.ns && prev.binNames == binNames && prev.readAllBins == record.readAllBins)
                {
                    // Can set repeat previous namespace/bin names to save space.
                    dataBuffer[dataOffset++] = 1; // repeat
                }
                else
                {
                    // Write full header, namespace and bin names.
                    dataBuffer[dataOffset++] = 0; // do not repeat

                    if (binNames != null && binNames.Length != 0)
                    {
                        dataBuffer[dataOffset++] = (byte)Command.INFO1_READ;
                        dataBuffer[dataOffset++] = 0; // pad
                        dataBuffer[dataOffset++] = 0; // pad
                        ByteUtil.ShortToBytes((ushort)binNames.Length, dataBuffer, dataOffset);
                        dataOffset += 2;
                        WriteField(key.ns, FieldType.NAMESPACE);

                        foreach (string binName in binNames)
                        {
                            WriteOperation(binName, Operation.Type.READ);
                        }
                    }
                    else
                    {
                        dataBuffer[dataOffset++] = (byte)(Command.INFO1_READ | (record.readAllBins ? Command.INFO1_GET_ALL : Command.INFO1_NOBINDATA));
                        dataBuffer[dataOffset++] = 0; // pad
                        dataBuffer[dataOffset++] = 0; // pad
                        ByteUtil.ShortToBytes(0, dataBuffer, dataOffset);
                        dataOffset += 2;
                        WriteField(key.ns, FieldType.NAMESPACE);
                    }
                    prev = record;
                }
            }

            // Write real field size.
            ByteUtil.IntToBytes((uint)(dataOffset - MSG_TOTAL_HEADER_SIZE - 4), dataBuffer, fieldSizeOffset);
            End();
        }
        public void SetBatchRead(BatchPolicy policy, Key[] keys, BatchNode batch, string[] binNames, int readAttr)
        {
            // Estimate full row size
            int[] offsets = batch.offsets;
            int max = batch.offsetsSize;
            int rowSize = 30 + FIELD_HEADER_SIZE + 31; // Row's header(30) + max namespace(31).
            int operationCount = 0;

            if (binNames != null)
            {
                foreach (string binName in binNames)
                {
                    EstimateOperationSize(binName);
                }
                rowSize += dataOffset;
                operationCount = binNames.Length;
            }

            // Estimate buffer size.
            Begin();
            dataOffset += FIELD_HEADER_SIZE + 5;

            string prevNamespace = null;

            for (int i = 0; i < max; i++)
            {
                Key key = keys[offsets[i]];

                // Try reference equality in hope that namespace for all keys is set from a fixed variable.
                if (key.ns == prevNamespace || (prevNamespace != null && prevNamespace.Equals(key.ns)))
                {
                    // Can set repeat previous namespace/bin names to save space.
                    dataOffset += 25;
                }
                else
                {
                    // Must write full header and namespace/bin names.
                    dataOffset += rowSize;
                    prevNamespace = key.ns;
                }
            }

            SizeBuffer();

            WriteHeader(policy, readAttr | Command.INFO1_BATCH, 0, 1, 0);
            int fieldSizeOffset = dataOffset;
            WriteFieldHeader(0, FieldType.BATCH_INDEX); // Need to update size at end

            ByteUtil.IntToBytes((uint)max, dataBuffer, dataOffset);
            dataOffset += 4;
            dataBuffer[dataOffset++] = (policy.allowInline) ? (byte)1 : (byte)0;
            prevNamespace = null;

            for (int i = 0; i < max; i++)
            {
                int index = offsets[i];
                ByteUtil.IntToBytes((uint)index, dataBuffer, dataOffset);
                dataOffset += 4;

                Key key = keys[index];
                byte[] digest = key.digest;
                Array.Copy(digest, 0, dataBuffer, dataOffset, digest.Length);
                dataOffset += digest.Length;

                // Try reference equality in hope that namespace for all keys is set from a fixed variable.
                if (key.ns == prevNamespace || (prevNamespace != null && prevNamespace.Equals(key.ns)))
                {
                    // Can set repeat previous namespace/bin names to save space.
                    dataBuffer[dataOffset++] = 1; // repeat
                }
                else
                {
                    // Write full header, namespace and bin names.
                    dataBuffer[dataOffset++] = 0; // do not repeat
                    dataBuffer[dataOffset++] = (byte)readAttr;
                    dataBuffer[dataOffset++] = 0; // pad
                    dataBuffer[dataOffset++] = 0; // pad
                    ByteUtil.ShortToBytes((ushort)operationCount, dataBuffer, dataOffset);
                    dataOffset += 2;
                    WriteField(key.ns, FieldType.NAMESPACE);

                    if (binNames != null)
                    {
                        foreach (string binName in binNames)
                        {
                            WriteOperation(binName, Operation.Type.READ);
                        }
                    }
                    prevNamespace = key.ns;
                }
            }

            // Write real field size.
            ByteUtil.IntToBytes((uint)(dataOffset - MSG_TOTAL_HEADER_SIZE - 4), dataBuffer, fieldSizeOffset);
            End();
        }
        public void Read(AerospikeClient client, BatchPolicy policy, string ns, string set, string accountId)
        {
            Record record = client.Join(policy,
                new Key(ns, set, accountId),
                new Join("tickers", ns, set));

            if (record == null)
            {
                throw new Exception("Failed to read: " + accountId);
            }

            this.accountId = accountId;
            byte[] positionsBytes = (byte[])record.GetValue("positions");
            Record[] records = (Record[])record.GetValue("tickers");

            if (positionsBytes != null)
            {
                MemoryStream ms = new MemoryStream(positionsBytes);
                BinaryReader reader = new BinaryReader(ms);
                int count = reader.ReadInt32();
                positions = new List<Position>(count);

                for (int i = 0; i < count; i++)
                {
                    positions.Add(new Position(reader, records[i]));
                }
            }
            else
            {
                positions = new List<Position>(0);
            }
        }
 /// <summary>
 /// Asynchronously read multiple record header data for specified keys in one batch call.
 /// Create listener, call asynchronous batch header get and return task monitor.
 /// <para>
 /// If a key is not found, the record will be null.
 /// The policy can be used to specify timeouts.
 /// </para>
 /// </summary>
 /// <param name="policy">generic configuration parameters, pass in null for defaults</param>
 /// <param name="token">cancellation token</param>
 /// <param name="keys">array of unique record identifiers</param>
 /// <exception cref="AerospikeException">if queue is full</exception>
 public Task<Record[]> GetHeader(BatchPolicy policy, CancellationToken token, Key[] keys)
 {
     RecordArrayListenerAdapter listener = new RecordArrayListenerAdapter(token);
     GetHeader(policy, listener, keys);
     return listener.Task;
 }
 /// <summary>
 /// Asynchronously read multiple record header data for specified keys in one batch call.
 /// Schedule the batch get header command with a channel selector and return.
 /// Another thread will process the command and send the results to the listener in a single call.
 /// <para>
 /// If a key is not found, the record will be null.
 /// The policy can be used to specify timeouts.
 /// </para>
 /// </summary>
 /// <param name="policy">generic configuration parameters, pass in null for defaults</param>
 /// <param name="listener">where to send results</param>
 /// <param name="keys">array of unique record identifiers</param>
 /// <exception cref="AerospikeException">if queue is full</exception>
 public void GetHeader(BatchPolicy policy, RecordArrayListener listener, Key[] keys)
 {
     if (keys.Length == 0)
     {
         listener.OnSuccess(keys, new Record[0]);
         return;
     }
     if (policy == null)
     {
         policy = batchPolicyDefault;
     }
     new AsyncBatchGetArrayExecutor(cluster, policy, listener, keys, null, Command.INFO1_READ | Command.INFO1_NOBINDATA);
 }
        public AsyncBatchReadSequenceCommand(
			AsyncMultiExecutor parent,
			AsyncCluster cluster,
			BatchNode batch,
			BatchPolicy policy,
			BatchSequenceListener listener,
			List<BatchRead> records
		)
            : base(parent, cluster, (AsyncNode)batch.node, false)
        {
            this.batch = batch;
            this.policy = policy;
            this.listener = listener;
            this.records = records;
        }
        public AsyncBatchGetSequenceExecutor(
			AsyncCluster cluster,
			BatchPolicy policy,
			RecordSequenceListener listener,
			Key[] keys,
			string[] binNames,
			int readAttr
		)
            : base(cluster, policy, keys)
        {
            this.listener = listener;

            // Create commands.
            AsyncMultiCommand[] tasks = new AsyncMultiCommand[base.taskSize];
            int count = 0;

            foreach (BatchNode batchNode in batchNodes)
            {
                if (batchNode.node.UseNewBatch(policy))
                {
                    // New batch
                    tasks[count++] = new AsyncBatchGetSequenceCommand(this, cluster, batchNode, policy, keys, binNames, listener, readAttr);
                }
                else
                {
                    // Old batch only allows one namespace per call.
                    foreach (BatchNode.BatchNamespace batchNamespace in batchNode.batchNamespaces)
                    {
                        tasks[count++] = new AsyncBatchGetSequenceDirect(this, cluster, (AsyncNode)batchNode.node, batchNamespace, policy, keys, binNames, listener, readAttr);
                    }
                }
            }
            // Dispatch commands to nodes.
            Execute(tasks, policy.maxConcurrentThreads);
        }
 //-------------------------------------------------------
 // Batch Read Operations
 //-------------------------------------------------------
 /// <summary>
 /// Asynchronously read multiple records for specified batch keys in one batch call.
 /// This method allows different namespaces/bins to be requested for each key in the batch.
 /// The returned records are located in the same list.
 /// <para>
 /// Create listener, call asynchronous batch get and return task monitor.
 /// This method requires Aerospike Server version >= 3.6.0.
 /// </para>
 /// </summary>
 /// <param name="policy">batch configuration parameters, pass in null for defaults</param>
 /// <param name="token">cancellation token</param>
 /// <param name="records">list of unique record identifiers and the bins to retrieve.</param>
 /// <exception cref="AerospikeException">if read fails</exception>
 public Task<List<BatchRead>> Get(BatchPolicy policy, CancellationToken token, List<BatchRead> records)
 {
     BatchListListenerAdapter listener = new BatchListListenerAdapter(token);
     Get(policy, listener, records);
     return listener.Task;
 }
        public AsyncBatchReadSequenceExecutor(
			AsyncCluster cluster,
			BatchPolicy policy,
			BatchSequenceListener listener,
			List<BatchRead> records
		)
        {
            this.listener = listener;

            // Create commands.
            List<BatchNode> batchNodes = BatchNode.GenerateList(cluster, policy, records);
            AsyncMultiCommand[] tasks = new AsyncMultiCommand[batchNodes.Count];
            int count = 0;

            foreach (BatchNode batchNode in batchNodes)
            {
                if (!batchNode.node.hasBatchIndex)
                {
                    throw new AerospikeException(ResultCode.PARAMETER_ERROR, "Requested command requires a server that supports new batch index protocol.");
                }
                tasks[count++] = new AsyncBatchReadSequenceCommand(this, cluster, batchNode, policy, listener, records);
            }
            // Dispatch commands to nodes.
            Execute(tasks, policy.maxConcurrentThreads);
        }
        public AsyncBatchGetSequenceCommand(
			AsyncMultiExecutor parent,
			AsyncCluster cluster,
			BatchNode batch,
			BatchPolicy policy,
			Key[] keys,
			string[] binNames,
			RecordSequenceListener listener,
			int readAttr
		)
            : base(parent, cluster, (AsyncNode)batch.node, false)
        {
            this.batch = batch;
            this.policy = policy;
            this.keys = keys;
            this.binNames = binNames;
            this.listener = listener;
            this.readAttr = readAttr;
        }
        public AsyncBatchExistsSequenceCommand(
			AsyncMultiExecutor parent,
			AsyncCluster cluster,
			BatchNode batch,
			BatchPolicy policy,
			Key[] keys,
			ExistsSequenceListener listener
		)
            : base(parent, cluster, (AsyncNode)batch.node, false)
        {
            this.batch = batch;
            this.policy = policy;
            this.keys = keys;
            this.listener = listener;
        }
 /// <summary>
 /// Asynchronously read multiple records for specified keys in one batch call.
 /// Schedule the get command with a channel selector and return.
 /// Another thread will process the command and send the results to the listener in multiple unordered calls.
 /// <para>
 /// If a key is not found, the record will be null.
 /// The policy can be used to specify timeouts.
 /// </para>
 /// </summary>
 /// <param name="policy">generic configuration parameters, pass in null for defaults</param>
 /// <param name="listener">where to send results</param>
 /// <param name="keys">array of unique record identifiers</param>
 /// <exception cref="AerospikeException">if queue is full</exception>
 public void Get(BatchPolicy policy, RecordSequenceListener listener, Key[] keys)
 {
     if (keys.Length == 0)
     {
         listener.OnSuccess();
         return;
     }
     if (policy == null)
     {
         policy = batchPolicyDefault;
     }
     new AsyncBatchGetSequenceExecutor(cluster, policy, listener, keys, null, Command.INFO1_READ | Command.INFO1_GET_ALL);
 }
 public BatchReadListCommand(BatchNode batch, BatchPolicy policy, List<BatchRead> records)
     : base(batch.node, false)
 {
     this.batch = batch;
     this.policy = policy;
     this.records = records;
 }
 /// <summary>
 /// Asynchronously check if multiple record keys exist in one batch call.
 /// Schedule the exists command with a channel selector and return.
 /// Another thread will process the command and send the results to the listener in multiple unordered calls.
 /// <para>
 /// The policy can be used to specify timeouts.
 /// </para>
 /// </summary>
 /// <param name="policy">generic configuration parameters, pass in null for defaults</param>
 /// <param name="listener">where to send results</param>
 /// <param name="keys">array of unique record identifiers</param>
 /// <exception cref="AerospikeException">if queue is full</exception>
 public void Exists(BatchPolicy policy, ExistsSequenceListener listener, Key[] keys)
 {
     if (keys.Length == 0)
     {
         listener.OnSuccess();
         return;
     }
     if (policy == null)
     {
         policy = batchPolicyDefault;
     }
     new AsyncBatchExistsSequenceExecutor(cluster, policy, keys, listener);
 }
 /// <summary>
 /// Asynchronously read multiple record headers and bins for specified keys in one batch call.
 /// Schedule the batch get command with a channel selector and return.
 /// Another thread will process the command and send the results to the listener in multiple unordered calls.
 /// <para>
 /// If a key is not found, the record will be null.
 /// The policy can be used to specify timeouts.
 /// </para>
 /// </summary>
 /// <param name="policy">generic configuration parameters, pass in null for defaults</param>
 /// <param name="listener">where to send results</param>
 /// <param name="keys">array of unique record identifiers</param>
 /// <param name="binNames">array of bins to retrieve</param>
 /// <exception cref="AerospikeException">if queue is full</exception>
 public void Get(BatchPolicy policy, RecordSequenceListener listener, Key[] keys, params string[] binNames)
 {
     if (keys.Length == 0)
     {
         listener.OnSuccess();
         return;
     }
     if (policy == null)
     {
         policy = batchPolicyDefault;
     }
     new AsyncBatchGetSequenceExecutor(cluster, policy, listener, keys, binNames, Command.INFO1_READ);
 }
 /// <summary>
 /// Asynchronously read multiple record headers and bins for specified keys in one batch call.
 /// Create listener, call asynchronous batch get and return task monitor.
 /// <para>
 /// If a key is not found, the record will be null.
 /// The policy can be used to specify timeouts.
 /// </para>
 /// </summary>
 /// <param name="policy">generic configuration parameters, pass in null for defaults</param>
 /// <param name="token">cancellation token</param>
 /// <param name="keys">array of unique record identifiers</param>
 /// <param name="binNames">array of bins to retrieve</param>
 /// <exception cref="AerospikeException">if queue is full</exception>
 public Task<Record[]> Get(BatchPolicy policy, CancellationToken token, Key[] keys, params string[] binNames)
 {
     RecordArrayListenerAdapter listener = new RecordArrayListenerAdapter(token);
     Get(policy, listener, keys, binNames);
     return listener.Task;
 }