public override RequestOp ToRequestOp() { TxnRequest txn = new TxnRequest(); if (cmps != null) { foreach (Cmp <object> cmp in cmps) { txn.Compare.Add(cmp.ToCompare()); } } if (thenOps != null) { foreach (Op thenOp in thenOps) { txn.Success.Add(thenOp.ToRequestOp()); } } if (elseOps != null) { foreach (Op elseOp in elseOps) { txn.Failure.Add(elseOp.ToRequestOp()); } } RequestOp op = new RequestOp(); op.RequestTxn = txn; return(op); }
/// <summary> /// Txn processes multiple requests in a single transaction in async. /// A txn request increments the revision of the key-value store /// and generates events with the same revision for every completed request. /// It is not allowed to modify the same key several times within one txn. /// </summary> /// <param name="request">The request to send to the server.</param> /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param> /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param> /// <param name="cancellationToken">An optional token for canceling the call.</param> /// <returns>The response received from the server.</returns> public async Task <TxnResponse> TransactionAsync(TxnRequest request, Grpc.Core.Metadata headers = null, DateTime?deadline = null, CancellationToken cancellationToken = default) { return(await CallEtcdAsync(async (connection) => await connection.kvClient .TxnAsync(request, headers, deadline, cancellationToken))); }
/// <summary> /// Txn processes multiple requests in a single transaction in async. /// A txn request increments the revision of the key-value store /// and generates events with the same revision for every completed request. /// It is not allowed to modify the same key several times within one txn. /// </summary> /// <param name="request"></param> /// <returns></returns> public async Task <TxnResponse> TransactionAsync(TxnRequest request, Metadata headers = null) { TxnResponse response = new TxnResponse(); bool success = false; int retryCount = 0; while (!success) { try { response = await _balancer.GetConnection().kvClient.TxnAsync(request, headers); success = true; } catch (RpcException ex) when(ex.StatusCode == StatusCode.Unavailable) { retryCount++; if (retryCount >= _balancer._numNodes) { throw ex; } } } return(response); }
/// <summary> /// Txn processes multiple requests in a single transaction in async. /// A txn request increments the revision of the key-value store /// and generates events with the same revision for every completed request. /// It is not allowed to modify the same key several times within one txn. /// </summary> /// <param name="request">The request to send to the server.</param> /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param> /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param> /// <param name="cancellationToken">An optional token for canceling the call.</param> /// <returns>The response received from the server.</returns> public async Task <TxnResponse> TransactionAsync(TxnRequest request, Grpc.Core.Metadata headers = null, DateTime?deadline = null, CancellationToken cancellationToken = default) { TxnResponse response = new TxnResponse(); bool success = false; int retryCount = 0; while (!success) { try { response = await _balancer.GetConnection().kvClient .TxnAsync(request, headers, deadline, cancellationToken); success = true; } catch (RpcException ex) when(ex.StatusCode == StatusCode.Unavailable) { retryCount++; if (retryCount >= _balancer._numNodes) { throw; } } } return(response); }
/// <summary> /// Txn processes multiple requests in a single transaction in async. /// A txn request increments the revision of the key-value store /// and generates events with the same revision for every completed request. /// It is not allowed to modify the same key several times within one txn. /// </summary> /// <param name="request"></param> /// <returns></returns> public async Task <TxnResponse> TransactionAsync(TxnRequest request) { try { return(await _kvClient.TxnAsync(request, _headers)); } catch (RpcException) { ResetConnection(); throw; } catch { throw; } }
/// <summary> /// Txn processes multiple requests in a single transaction. /// A txn request increments the revision of the key-value store /// and generates events with the same revision for every completed request. /// It is not allowed to modify the same key several times within one txn. /// </summary> /// <param name="request"></param> /// <returns></returns> public TxnResponse Transaction(TxnRequest request) { try { return(_kvClient.Txn(request, _headers)); } catch (RpcException) { ResetConnection(); throw; } catch { throw; } }
public bool LockLeader(string serverUri, long leaseId) { try { using (IEtcdCompoundClient client = _etcdCompoundClientFactory.CreateClient(serverUri)) { var transactionRequest = new TxnRequest(); transactionRequest.Compare.Add ( new Compare { Key = ByteString.CopyFromUtf8(KEY_LEADER_ELECTION), Target = Compare.Types.CompareTarget.Create, Result = Compare.Types.CompareResult.Greater, CreateRevision = 0 } ); transactionRequest.Failure.Add(new RequestOp { RequestPut = new PutRequest { Key = ByteString.CopyFromUtf8(KEY_LEADER_ELECTION), Value = ByteString.CopyFromUtf8(leaseId.ToString()), Lease = leaseId } }); _ = client.Transaction(transactionRequest); string keyValueInDatabase = GetKey(client, KEY_LEADER_ELECTION); if (String.IsNullOrEmpty(keyValueInDatabase)) { return(false); } return(Convert.ToInt64(keyValueInDatabase) == leaseId); } } catch (Exception ex) { _log.Error($"Leader locking fo lease {leaseId} exception: {ex}"); return(false); } }
public void Transaction() { Mock <IEtcdClient> etcdClientMock = new Mock <IEtcdClient>(); Mock <IDisposable> disposableMock = new Mock <IDisposable>(); EtcdCompoundClient client = new EtcdCompoundClient(etcdClientMock.Object, disposableMock.Object); Fixture fixture = new Fixture(); TxnRequest txnRequest = fixture.Create <TxnRequest>(); TxnResponse response = fixture.Create <TxnResponse>(); etcdClientMock.Setup(p => p.Transaction(txnRequest, null, null, CancellationToken.None)).Returns(response); TxnResponse actualResponse = client.Transaction(txnRequest); etcdClientMock.Verify(p => p.Transaction(txnRequest, null, null, CancellationToken.None), Times.Once); Assert.AreSame(response, actualResponse); }
private TxnRequest ToTxnRequest() { TxnRequest requestBuilder = new TxnRequest(); foreach (Cmp <object> c in this.cmpList) { requestBuilder.Compare.Add(c.ToCompare()); } foreach (Op o in this.successOpList) { requestBuilder.Success.Add(o.ToRequestOp()); } foreach (Op o in this.failureOpList) { requestBuilder.Failure.Add(o.ToRequestOp()); } return(requestBuilder); }
private static async Task <bool> TryPut(string key, string value, long lease) { var request = new TxnRequest(); request.Success.Add(new RequestOp { RequestPut = new PutRequest { Key = ByteString.CopyFromUtf8(key), Value = ByteString.CopyFromUtf8(value), Lease = lease } }); request.Compare.Add(new Compare { Version = 0, Key = ByteString.CopyFromUtf8(key) }); request.Failure.Add(new RequestOp[0]); var response = await EtcdClient.TransactionAsync(request); return(response.Succeeded); }
/// <summary> /// Txn processes multiple requests in a single transaction. /// A txn request increments the revision of the key-value store /// and generates events with the same revision for every completed request. /// It is not allowed to modify the same key several times within one txn. /// </summary> /// <param name="request">The request to send to the server.</param> /// <param name="headers">The initial metadata to send with the call. This parameter is optional.</param> /// <param name="deadline">An optional deadline for the call. The call will be cancelled if deadline is hit.</param> /// <param name="cancellationToken">An optional token for canceling the call.</param> /// <returns>The response received from the server.</returns> public TxnResponse Transaction(TxnRequest request, Grpc.Core.Metadata headers = null, DateTime?deadline = null, CancellationToken cancellationToken = default) { return(CallEtcd((connection) => connection.kvClient.Txn(request, headers, deadline, cancellationToken))); }
/// <summary> /// Txn processes multiple requests in a single transaction in async. /// A txn request increments the revision of the key-value store /// and generates events with the same revision for every completed request. /// It is not allowed to modify the same key several times within one txn. /// </summary> /// <param name="request"></param> /// <returns></returns> public async Task <TxnResponse> TransactionAsync(TxnRequest request, Metadata headers = null) { return(await _balancer.GetConnection().kvClient.TxnAsync(request, headers)); }
/// <summary> /// Txn processes multiple requests in a single transaction. /// A txn request increments the revision of the key-value store /// and generates events with the same revision for every completed request. /// It is not allowed to modify the same key several times within one txn. /// </summary> /// <param name="request"></param> /// <returns></returns> public TxnResponse Transaction(TxnRequest request, Metadata headers = null) { return(_balancer.GetConnection().kvClient.Txn(request, headers)); }
/// <summary> /// Add/update a configuration reocrd in the repository /// </summary> /// <param name="configurationItem">The configuration record to add or update</param> /// <param name="force">Force a set (overwrite) even if configuraton item already exists with a different version</param> public virtual async Task Set(TModel configurationItem, bool force = false) { if (configurationItem == null) { throw new ArgumentNullException(nameof(configurationItem)); } //Set created timestamp for version 0 if (configurationItem.Version == 0 || force) { configurationItem.CreatedOn = DateTimeOffset.UtcNow; } //Otherwise set modified timestamp else { configurationItem.ModifiedOn = DateTimeOffset.UtcNow; } //Create the etcd key for the configuration item var etcdKey = CreateEtcdKey(configurationItem); //Serialise configuration item as JSON to persist to etcd var json = JsonConvert.SerializeObject(configurationItem, typeof(TModel), _jsonSerializerSettings); //Ensure the repository is initialised before retreiving item await _readyTask.ConfigureAwait(false); //If we force an update then we just put the value without a check if (force) { //Put the key/value into etcd var setReponse = await _etcdClient.PutAsync(etcdKey, json).ConfigureAwait(false); //Update the configuration item version configurationItem.Version = setReponse.Header.Revision; } //If we do not force update we need to do a CAS (check and set) which will eliminate concurrency issues and accidental overwrites else { //Create a transaction that checks the ModRevision is the same as the configuration item before performing the put operation var transReq = new TxnRequest(); if (configurationItem.Version == 0) { transReq.Compare.Add(new Compare { Key = Google.Protobuf.ByteString.CopyFromUtf8(etcdKey), Result = Compare.Types.CompareResult.Equal, CreateRevision = configurationItem.Version, Target = Compare.Types.CompareTarget.Create }); } else { transReq.Compare.Add(new Compare { Key = Google.Protobuf.ByteString.CopyFromUtf8(etcdKey), Result = Compare.Types.CompareResult.Equal, ModRevision = configurationItem.Version, Target = Compare.Types.CompareTarget.Mod }); } transReq.Success.Add(new RequestOp { RequestPut = new PutRequest { Key = Google.Protobuf.ByteString.CopyFromUtf8(etcdKey), Value = Google.Protobuf.ByteString.CopyFromUtf8(json) } }); //Execute transaction var transResponse = await _etcdClient.TransactionAsync(transReq); //Check the transaction succeeded if (transResponse.Succeeded) { //Update the configuration item version configurationItem.Version = transResponse.Responses[0].ResponsePut.Header.Revision; } else { throw new ArgumentException("Unable to set configuration item, either the specified item does not exist or the version specified was incorrect."); } } }
public TxnResponse Transaction(TxnRequest request) { return(_etcdClient.Transaction(request)); }