public ExecutorThread(Executor parent, MultiCommand command) { this.parent = parent; this.command = command; }
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); } }
//------------------------------------------------------- // Batch Read Operations //------------------------------------------------------- /// <summary> /// 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. /// The policy can be used to specify timeouts and maximum concurrent threads. /// This method requires Aerospike Server version >= 3.6.0. /// </summary> /// <param name="policy">batch configuration parameters, pass in null for defaults</param> /// <param name="records">list of unique record identifiers and the bins to retrieve. /// The returned records are located in the same list.</param> /// <exception cref="AerospikeException">if read fails</exception> public void Get(BatchPolicy policy, List<BatchRead> records) { if (records.Count == 0) { return; } if (policy == null) { policy = batchPolicyDefault; } List<BatchNode> batchNodes = BatchNode.GenerateList(cluster, policy, records); if (policy.maxConcurrentThreads == 1 || batchNodes.Count <= 1) { // Run batch requests sequentially in same thread. 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."); } MultiCommand command = new BatchReadListCommand(batchNode, policy, records); command.Execute(); } } else { // Run batch requests in parallel in separate threads. // // Multiple threads write to the record list, 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); 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."); } MultiCommand command = new BatchReadListCommand(batchNode, policy, records); executor.AddCommand(command); } executor.Execute(policy.maxConcurrentThreads); } }
//---------------------------------------------------------- // Query/Execute UDF (Supported by Aerospike 3 servers only) //---------------------------------------------------------- /// <summary> /// Apply user defined function on records that match the statement filter. /// Records are not returned to the client. /// This asynchronous server call will return before command is complete. /// The user can optionally wait for command completion by using the returned /// ExecuteTask instance. /// <para> /// This method is only supported by Aerospike 3 servers. /// </para> /// </summary> /// <param name="policy">configuration parameters, pass in null for defaults</param> /// <param name="statement">record filter</param> /// <param name="packageName">server package where user defined function resides</param> /// <param name="functionName">function name</param> /// <param name="functionArgs">to pass to function name, if any</param> /// <exception cref="AerospikeException">if command fails</exception> public ExecuteTask Execute(WritePolicy policy, Statement statement, string packageName, string functionName, params Value[] functionArgs) { if (policy == null) { policy = writePolicyDefault; } statement.SetAggregateFunction(packageName, functionName, functionArgs); statement.Prepare(false); Node[] nodes = cluster.Nodes; if (nodes.Length == 0) { throw new AerospikeException(ResultCode.SERVER_NOT_AVAILABLE, "Command failed because cluster is empty."); } Executor executor = new Executor(nodes.Length); foreach (Node node in nodes) { ServerCommand command = new ServerCommand(node, policy, statement); executor.AddCommand(command); } executor.Execute(nodes.Length); return new ExecuteTask(cluster, policy, statement); }
//------------------------------------------------------- // 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); } } }
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); } }
public BatchReadListCommand(Executor parent, BatchNode batch, BatchPolicy policy, List <BatchRead> records) : base(parent, batch, policy) { this.records = records; }