/// <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; }
/// <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(); } }