/// <summary>
        /// Called exactly once per multiplexing pool, when the first connection is opened, with two goals:
        /// 1. Load types and bind the pool-wide type mapper (necessary for binding parameters)
        /// 2. Cause any connection exceptions (e.g. bad username) to be thrown from NpgsqlConnection.Open
        /// </summary>
        internal async Task BootstrapMultiplexing(NpgsqlConnection conn, NpgsqlTimeout timeout, bool async, CancellationToken cancellationToken = default)
        {
            Debug.Assert(_multiplexing);

            var connector =
                await conn.StartBindingScope(ConnectorBindingScope.Connection, timeout, async, cancellationToken);

            using var _ = Defer(() => conn.EndBindingScope(ConnectorBindingScope.Connection));

            // Somewhat hacky. Extract the connector's type mapper as our pool-wide mapper,
            // and have the connector rebind to ensure it has a different instance.
            // The latter isn't strictly necessary (type mappers should always be usable
            // concurrently) but just in case.
            MultiplexingTypeMapper = connector.TypeMapper;
            connector.RebindTypeMapper();

            IsBootstrapped = true;
        }
Example #2
0
        /// <summary>
        /// Called exactly once per multiplexing pool, when the first connection is opened, with two goals:
        /// 1. Load types and bind the pool-wide type mapper (necessary for binding parameters)
        /// 2. Cause any connection exceptions (e.g. bad username) to be thrown from NpgsqlConnection.Open
        /// </summary>
        internal async Task BootstrapMultiplexing(NpgsqlConnection conn, NpgsqlTimeout timeout, bool async, CancellationToken cancellationToken = default)
        {
            Debug.Assert(_multiplexing);

            var hasSemaphore = async
                ? await _bootstrapSemaphore !.WaitAsync(timeout.TimeLeft, cancellationToken)
                : _bootstrapSemaphore !.Wait(timeout.TimeLeft, cancellationToken);

            // We've timed out - calling Check, to throw the correct exception
            if (!hasSemaphore)
            {
                timeout.Check();
            }

            try
            {
                if (IsBootstrapped)
                {
                    return;
                }

                var connector = await conn.StartBindingScope(ConnectorBindingScope.Connection, timeout, async, cancellationToken);

                using var _ = Defer(() => conn.EndBindingScope(ConnectorBindingScope.Connection));

                // Somewhat hacky. Extract the connector's type mapper as our pool-wide mapper,
                // and have the connector rebind to ensure it has a different instance.
                // The latter isn't strictly necessary (type mappers should always be usable
                // concurrently) but just in case.
                MultiplexingTypeMapper = connector.TypeMapper;
                connector.RebindTypeMapper();

                IsBootstrapped = true;
            }
            finally
            {
                _bootstrapSemaphore !.Release();
            }
        }