/// <summary>
        /// Handles a connection to a new cluster.
        /// </summary>
#pragma warning disable IDE0060 // Remove unused parameters
#pragma warning disable CA1801  // Review unused parameters
        // unused parameters are required, this is an event handler
        public ValueTask OnConnectionOpened(MemberConnection connection, bool isFirstEver, bool isFirst, bool isNewCluster)
#pragma warning restore CA1801
#pragma warning restore IDE0060
        {
            if (!isNewCluster)
            {
                return(default);
        /// <summary>
        /// Handles a closed connection.
        /// </summary>
        /// <param name="connection">The connection.</param>
        /// <param name="wasLast">Whether the connection was the last one.</param>
        public ValueTask OnConnectionClosed(MemberConnection connection, bool wasLast)
        {
            var args = new ConnectionClosedEventArgs(wasLast);

            // trigger ConnectionRemoved event
            return(ForEachHandler <ConnectionClosedEventHandler, ConnectionClosedEventArgs>(
                       (handler, sender, a) => handler.HandleAsync(sender, a), args));
        }
Example #3
0
        /// <summary>
        /// Begins the transaction.
        /// </summary>
        public async Task BeginAsync()
        {
            if (State != TransactionState.None)
            {
                throw new InvalidOperationException("The transaction context is already involved in a transaction.");
            }

            var asyncContext = AsyncContext.Current;

            lock (_inTransactionMutex)
            {
                // this is used to prevent an asynchronous context from being in multiple (thus nested) transactions,
                // it was implemented, before async, via a [ThreadStatic] boolean (when everything was bound to
                // threads) which cannot be appropriate anymore. instead we move it to the async context.

                if (asyncContext.InTransaction)
                {
                    throw new InvalidOperationException("Nested transactions are not supported.");
                }
                asyncContext.InTransaction = true;
            }

            _connection = _cluster.Members.GetRandomConnection();
            if (_connection == null)
            {
                throw _cluster.State.ThrowClientOfflineException();
            }

            _threadId = ContextId;
            //_startTime = Clock.Milliseconds;

            HConsole.WriteLine(this, $"Begin transaction on context #{ContextId}");

            try
            {
                // codec wants 0 for server config, -1 for infinite (?)
                var timeoutMs = _options.Timeout.RoundedMilliseconds(false);

                var requestMessage  = TransactionCreateCodec.EncodeRequest(timeoutMs, _options.Durability, (int)_options.Type, ContextId);
                var responseMessage = await _cluster.Messaging.SendToMemberAsync(requestMessage, _connection).CfAwait();

                TransactionId = TransactionCreateCodec.DecodeResponse(responseMessage).Response;
                State         = TransactionState.Active;
            }
            catch
            {
                lock (_inTransactionMutex) asyncContext.InTransaction = false;
                _threadId = 0;
                //_startTime = 0;
                TransactionId = default;
                State         = TransactionState.None;
                throw;
            }
        }
        public async Task Auth()
        {
            // need to start a real server (not the RC thing!)

            //var address = NetworkAddress.Parse("sgay-l4");
            var address = NetworkAddress.Parse("localhost");

            HConsole.Configure(this, config => config.SetIndent(0).SetPrefix("TEST"));
            HConsole.WriteLine(this, "Begin");

            HConsole.WriteLine(this, "Start client ");
            var client1 = new MemberConnection(address, new MessagingOptions(), new SocketOptions(), new SslOptions(), new Int64Sequence(), new NullLoggerFactory());
            await client1.ConnectAsync(CancellationToken.None).CAF();

            // RC assigns a GUID but the default cluster name is 'dev'
            var clusterName          = "dev";
            var username             = (string)null; // null
            var password             = (string)null; // null
            var clientId             = Guid.NewGuid();
            var clientType           = "CSP";        // CSharp
            var serializationVersion = (byte)0x01;
            var clientVersion        = "4.0";
            var clientName           = "hz.client_0";
            var labels         = new HashSet <string>();
            var requestMessage = ClientAuthenticationCodec.EncodeRequest(clusterName, username, password, clientId, clientType, serializationVersion, clientVersion, clientName, labels);

            HConsole.WriteLine(this, "Send auth request");
            var invocation      = new Invocation(requestMessage, new MessagingOptions(), null, CancellationToken.None);
            var responseMessage = await client1.SendAsync(invocation, CancellationToken.None).CAF();

            HConsole.WriteLine(this, "Rcvd auth response " +
                               HConsole.Lines(this, 1, responseMessage.Dump()));
            var response = ClientAuthenticationCodec.DecodeResponse(responseMessage);

            var status = (AuthenticationStatus)response.Status;

            NUnit.Framework.Assert.AreEqual(AuthenticationStatus.Authenticated, status);

            HConsole.WriteLine(this, "Stop client");
            await client1.DisposeAsync().CAF();

            HConsole.WriteLine(this, "End");
            await Task.Delay(100).CAF();
        }
        /// <summary>
        /// Handles an opened connection.
        /// </summary>
        /// <param name="connection">The connection.</param>
        /// <param name="isFirst">Whether the connection is the first one.</param>
        /// <param name="isNewCluster">Whether the cluster is a new/different cluster.</param>
        public async ValueTask OnConnectionOpened(MemberConnection connection, bool isFirst, bool isNewCluster)
        {
            // if it is the first connection, subscribe to events according to options
            if (isFirst)
            {
                // FIXME should this be cancelable?
                var cancellationToken = CancellationToken.None;
                foreach (var subscriber in _options.Subscribers)
                {
                    await subscriber.SubscribeAsync(this, cancellationToken).CfAwait();
                }
            }

            var args = new ConnectionOpenedEventArgs(isFirst);

            // trigger ConnectionOpened event
            await ForEachHandler <ConnectionOpenedEventHandler, ConnectionOpenedEventArgs>(
                (handler, sender, a) => handler.HandleAsync(sender, a), args).CfAwait();
        }
        public async Task Test()
        {
            using var _ = HConsoleForTest();

            var options = HazelcastOptions.Build();

            options.Messaging.RetryTimeoutSeconds = 1;

            var loggerFactory = new NullLoggerFactory();

            var address = NetworkAddress.Parse("127.0.0.1:11000");

            var state = new ServerState
            {
                Id       = 0,
                MemberId = Guid.NewGuid(),
                Address  = address
            };

            await using var server = new Server(address, ServerHandler, loggerFactory, state, "0")
                        {
                            MemberId = state.MemberId,
                        };
            await server.StartAsync();

            var serializationService = HazelcastClientFactory.CreateSerializationService(options.Serialization, loggerFactory);
            var authenticator        = new Authenticator(options.Authentication, serializationService);

            ISequence <int>  connectionIdSequence  = new Int32Sequence();
            ISequence <long> correlationIdSequence = new Int64Sequence();

            var memberConnection = new MemberConnection(address, authenticator,
                                                        options.Messaging, options.Networking, options.Networking.Ssl,
                                                        connectionIdSequence, correlationIdSequence,
                                                        loggerFactory);

            var memberConnectionHasClosed = false;

            memberConnection.Closed += connection =>
            {
                memberConnectionHasClosed = true;
                return(default);
        /// <summary>
        /// Creates all known <see cref="IDistributedObject"/> on a cluster.
        /// </summary>
        /// <returns>A task that will complete when the state has been sent.</returns>
        /// <remarks>
        /// <para>This is used when connecting to a new cluster.</para>
        /// </remarks>
        public async ValueTask CreateAllAsync(MemberConnection connection)
        {
            await foreach (var(key, _) in _objects)
            {
                // if the connection goes down, stop
                if (!connection.Active)
                {
                    return;
                }

                try
                {
                    var requestMessage = ClientCreateProxyCodec.EncodeRequest(key.Name, key.ServiceName);
                    await _cluster.Messaging.SendToMemberAsync(requestMessage, connection).CfAwait();
                }
                catch (Exception e)
                {
                    _logger.LogError(e, $"Failed to create ({key}) distributed object on new cluster.");
                }
            }
        }
 public HTxDictionary(string name, DistributedObjectFactory factory, Cluster cluster, MemberConnection transactionClientConnection, Guid transactionId, ISerializationService serializationService, ILoggerFactory loggerFactory)
     : base(HDictionary.ServiceName, name, factory, cluster, transactionClientConnection, transactionId, serializationService, loggerFactory)
 {
 }
Example #9
0
 /// <summary>
 /// Handles a connection to a new cluster.
 /// </summary>
 public ValueTask OnConnectionOpened(MemberConnection connection, bool isFirst, bool isNewCluster)
 {
     if (!isNewCluster)
     {
         return(default);
 /// <summary>
 /// Initializes a new instance of the <see cref="ConnectionClosedEventArgs"/> class.
 /// </summary>
 /// <param name="connection">The connection that was closed.</param>
 public ConnectionClosedEventArgs(MemberConnection connection)
 {
     Connection = connection;
 }
 /// <summary>
 /// Initializes a new instance of the <see cref="TransactionalDistributedObjectBase"/> class.
 /// </summary>
 /// <param name="serviceName">the name of the service managing this object.</param>
 /// <param name="name">The unique name of the object.</param>
 /// <param name="factory">The factory that owns this object.</param>
 /// <param name="cluster">A cluster.</param>
 /// <param name="transactionClientConnection">The client connection supporting the transaction.</param>
 /// <param name="transactionId">The unique identifier of the transaction.</param>
 /// <param name="serializationService">A serialization service.</param>
 /// <param name="loggerFactory">A logger factory.</param>
 protected TransactionalDistributedObjectBase(string serviceName, string name, DistributedObjectFactory factory, Cluster cluster, MemberConnection transactionClientConnection, Guid transactionId, SerializationService serializationService, ILoggerFactory loggerFactory)
     : base(serviceName, name, factory, cluster, serializationService, loggerFactory)
 {
     TransactionId = transactionId;
     TransactionClientConnection = transactionClientConnection;
 }
 public HTxMultiMap(string name, DistributedObjectFactory factory, Cluster cluster, MemberConnection transactionClientConnection, Guid transactionId, SerializationService serializationService, ILoggerFactory loggerFactory)
     : base(ServiceNames.MultiMap, name, factory, cluster, transactionClientConnection, transactionId, serializationService, loggerFactory)
 {
 }
Example #13
0
 /// <summary>
 /// Initializes a new instance of the <see cref="ConnectionOpenedEventArgs"/> class.
 /// </summary>
 /// <param name="connection">The connection that was opened.</param>
 /// <param name="isNewCluster">Whether the connection is the first connection to a new cluster.</param>
 public ConnectionOpenedEventArgs(MemberConnection connection, bool isNewCluster)
 {
     Connection   = connection;
     IsNewCluster = isNewCluster;
 }