示例#1
0
            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);
            }
示例#2
0
 /// <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)));
 }
示例#3
0
        /// <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);
        }
示例#4
0
        /// <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);
        }
示例#5
0
 /// <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;
     }
 }
示例#6
0
 /// <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;
     }
 }
示例#7
0
        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);
        }
示例#9
0
        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);
        }
示例#11
0
 /// <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)));
 }
示例#12
0
 /// <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));
 }
示例#13
0
 /// <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));
 }
示例#14
0
        /// <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));
 }