Skip to content

Commit

Permalink
Merge branch 'hotfix/4.0.8'
Browse files Browse the repository at this point in the history
  • Loading branch information
YohDeadfall committed Jul 18, 2019
2 parents 4ae8325 + 7f1802a commit 9c1a1d5
Show file tree
Hide file tree
Showing 22 changed files with 180 additions and 77 deletions.
2 changes: 1 addition & 1 deletion .appveyor.yml
@@ -1,5 +1,5 @@
image: Visual Studio 2017 image: Visual Studio 2017
version: 4.0.7-{build} version: 4.0.8-{build}
environment: environment:
global: global:
DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true
Expand Down
1 change: 1 addition & 0 deletions Npgsql.sln.DotSettings
Expand Up @@ -9,6 +9,7 @@
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_ACCESSORHOLDER_ATTRIBUTE_ON_SAME_LINE_EX/@EntryValue">NEVER</s:String> <s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_ACCESSORHOLDER_ATTRIBUTE_ON_SAME_LINE_EX/@EntryValue">NEVER</s:String>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SPACE_AFTER_TYPECAST_PARENTHESES/@EntryValue">False</s:Boolean> <s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SPACE_AFTER_TYPECAST_PARENTHESES/@EntryValue">False</s:Boolean>
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SPACE_WITHIN_SINGLE_LINE_ARRAY_INITIALIZER_BRACES/@EntryValue">True</s:Boolean> <s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/SPACE_WITHIN_SINGLE_LINE_ARRAY_INITIALIZER_BRACES/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpUseContinuousIndentInsideBracesMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=PGTZ/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=PGTZ/@EntryIndexedValue">True</s:Boolean>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=GIS/@EntryIndexedValue">GIS</s:String> <s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=GIS/@EntryIndexedValue">GIS</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=GSS/@EntryIndexedValue">GSS</s:String> <s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=GSS/@EntryIndexedValue">GSS</s:String>
Expand Down
2 changes: 1 addition & 1 deletion src/Npgsql.GeoJSON/Npgsql.GeoJSON.csproj
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">


<PropertyGroup> <PropertyGroup>
<VersionPrefix>4.0.7</VersionPrefix> <VersionPrefix>4.0.8</VersionPrefix>
<Description>GeoJSON plugin for Npgsql, allowing mapping of PostGIS geometry types to GeoJSON types.</Description> <Description>GeoJSON plugin for Npgsql, allowing mapping of PostGIS geometry types to GeoJSON types.</Description>
<Authors>Yoh Deadfall, Shay Rojansky</Authors> <Authors>Yoh Deadfall, Shay Rojansky</Authors>
<Copyright>Copyright 2019 © The Npgsql Development Team</Copyright> <Copyright>Copyright 2019 © The Npgsql Development Team</Copyright>
Expand Down
2 changes: 1 addition & 1 deletion src/Npgsql.Json.NET/Npgsql.Json.NET.csproj
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">


<PropertyGroup> <PropertyGroup>
<VersionPrefix>4.0.7</VersionPrefix> <VersionPrefix>4.0.8</VersionPrefix>
<Description>Json.NET plugin for Npgsql, allowing transparent serialization/deserialization of JSON objects directly to and from the database.</Description> <Description>Json.NET plugin for Npgsql, allowing transparent serialization/deserialization of JSON objects directly to and from the database.</Description>
<Authors>Shay Rojansky</Authors> <Authors>Shay Rojansky</Authors>
<Copyright>Copyright 2019 © The Npgsql Development Team</Copyright> <Copyright>Copyright 2019 © The Npgsql Development Team</Copyright>
Expand Down
2 changes: 1 addition & 1 deletion src/Npgsql.LegacyPostgis/Npgsql.LegacyPostgis.csproj
@@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<VersionPrefix>4.0.7</VersionPrefix> <VersionPrefix>4.0.8</VersionPrefix>
<Description>PostGIS plugin for Npgsql, allowing mapping of PostGIS types to the legacy types (e.g. PostgisPoint).</Description> <Description>PostGIS plugin for Npgsql, allowing mapping of PostGIS types to the legacy types (e.g. PostgisPoint).</Description>
<Authors>Shay Rojansky</Authors> <Authors>Shay Rojansky</Authors>
<Copyright>Copyright 2019 © The Npgsql Development Team</Copyright> <Copyright>Copyright 2019 © The Npgsql Development Team</Copyright>
Expand Down
2 changes: 1 addition & 1 deletion src/Npgsql.NetTopologySuite/Npgsql.NetTopologySuite.csproj
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">


<PropertyGroup> <PropertyGroup>
<VersionPrefix>4.0.7</VersionPrefix> <VersionPrefix>4.0.8</VersionPrefix>
<Description>NetTopologySuite plugin for Npgsql, allowing mapping of PostGIS geometry types to NetTopologySuite types.</Description> <Description>NetTopologySuite plugin for Npgsql, allowing mapping of PostGIS geometry types to NetTopologySuite types.</Description>
<Authors>Yoh Deadfall, Shay Rojansky</Authors> <Authors>Yoh Deadfall, Shay Rojansky</Authors>
<Copyright>Copyright 2019 © The Npgsql Development Team</Copyright> <Copyright>Copyright 2019 © The Npgsql Development Team</Copyright>
Expand Down
2 changes: 1 addition & 1 deletion src/Npgsql.NodaTime/Npgsql.NodaTime.csproj
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">


<PropertyGroup> <PropertyGroup>
<VersionPrefix>4.0.7</VersionPrefix> <VersionPrefix>4.0.8</VersionPrefix>
<Description>NodaTime plugin for Npgsql, allowing mapping of PostgreSQL date/time types to NodaTime types.</Description> <Description>NodaTime plugin for Npgsql, allowing mapping of PostgreSQL date/time types to NodaTime types.</Description>
<Authors>Shay Rojansky</Authors> <Authors>Shay Rojansky</Authors>
<Copyright>Copyright 2019 © The Npgsql Development Team</Copyright> <Copyright>Copyright 2019 © The Npgsql Development Team</Copyright>
Expand Down
2 changes: 1 addition & 1 deletion src/Npgsql.RawPostgis/Npgsql.RawPostgis.csproj
@@ -1,6 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<VersionPrefix>4.0.7</VersionPrefix> <VersionPrefix>4.0.8</VersionPrefix>
<Description>PostGIS plugin for Npgsql, allowing raw byte access to PostGIS ypes.</Description> <Description>PostGIS plugin for Npgsql, allowing raw byte access to PostGIS ypes.</Description>
<Authors>Shay Rojansky</Authors> <Authors>Shay Rojansky</Authors>
<Copyright>Copyright 2019 © The Npgsql Development Team</Copyright> <Copyright>Copyright 2019 © The Npgsql Development Team</Copyright>
Expand Down
36 changes: 23 additions & 13 deletions src/Npgsql/ConnectorPool.cs
@@ -1,4 +1,4 @@
#region License #region License
// The PostgreSQL License // The PostgreSQL License
// //
// Copyright (C) 2018 The Npgsql Development Team // Copyright (C) 2018 The Npgsql Development Team
Expand Down Expand Up @@ -84,7 +84,7 @@ internal struct PoolState
[FieldOffset(2)] [FieldOffset(2)]
internal short Busy; internal short Busy;
[FieldOffset(4)] [FieldOffset(4)]
internal short Waiting; internal int Waiting;
[FieldOffset(0)] [FieldOffset(0)]
internal long All; internal long All;


Expand All @@ -108,6 +108,7 @@ public override string ToString()
/// </summary> /// </summary>
int _clearCounter; int _clearCounter;


static readonly TimerCallback PruningTimerCallback = PruneIdleConnectors;
[CanBeNull] [CanBeNull]
Timer _pruningTimer; Timer _pruningTimer;
readonly TimeSpan _pruningInterval; readonly TimeSpan _pruningInterval;
Expand All @@ -123,6 +124,9 @@ public override string ToString()


internal ConnectorPool(NpgsqlConnectionStringBuilder settings, string connString) internal ConnectorPool(NpgsqlConnectionStringBuilder settings, string connString)
{ {
Debug.Assert(PoolSizeLimit <= short.MaxValue,
"PoolSizeLimit cannot be larger than short.MaxValue unless PoolState is refactored to hold larger values.");

if (settings.MaxPoolSize < settings.MinPoolSize) if (settings.MaxPoolSize < settings.MinPoolSize)
throw new ArgumentException($"Connection can't have MaxPoolSize {settings.MaxPoolSize} under MinPoolSize {settings.MinPoolSize}"); throw new ArgumentException($"Connection can't have MaxPoolSize {settings.MaxPoolSize} under MinPoolSize {settings.MinPoolSize}");


Expand Down Expand Up @@ -306,7 +310,7 @@ internal async ValueTask<NpgsqlConnector> AllocateLong(NpgsqlConnection conn, Np
// Start the pruning timer if we're above MinPoolSize // Start the pruning timer if we're above MinPoolSize
if (_pruningTimer == null && newState.Total > _min) if (_pruningTimer == null && newState.Total > _min)
{ {
var newPruningTimer = new Timer(PruneIdleConnectors); var newPruningTimer = new Timer(PruningTimerCallback, this, -1, -1);
if (Interlocked.CompareExchange(ref _pruningTimer, newPruningTimer, null) == null) if (Interlocked.CompareExchange(ref _pruningTimer, newPruningTimer, null) == null)
newPruningTimer.Change(_pruningInterval, _pruningInterval); newPruningTimer.Change(_pruningInterval, _pruningInterval);
else else
Expand All @@ -323,7 +327,11 @@ internal async ValueTask<NpgsqlConnector> AllocateLong(NpgsqlConnection conn, Np
{ {
// Pool is exhausted. Increase the waiting count while atomically making sure the busy count // Pool is exhausted. Increase the waiting count while atomically making sure the busy count
// doesn't decrease (otherwise we have a new idle connector). // doesn't decrease (otherwise we have a new idle connector).
newState.Waiting++; checked
{
newState.Waiting++;
}

CheckInvariants(newState); CheckInvariants(newState);
if (Interlocked.CompareExchange(ref State.All, newState.All, state.All) != state.All) if (Interlocked.CompareExchange(ref State.All, newState.All, state.All) != state.All)
{ {
Expand Down Expand Up @@ -351,7 +359,7 @@ internal async ValueTask<NpgsqlConnector> AllocateLong(NpgsqlConnection conn, Np
// Use Task.Delay to implement the timeout, but cancel the timer if we actually // Use Task.Delay to implement the timeout, but cancel the timer if we actually
// do complete successfully // do complete successfully
var delayCancellationToken = new CancellationTokenSource(); var delayCancellationToken = new CancellationTokenSource();
using (cancellationToken.Register(() => delayCancellationToken.Cancel())) using (cancellationToken.Register(s => ((CancellationTokenSource)s).Cancel(), delayCancellationToken))
{ {
var timeLeft = timeout.TimeLeft; var timeLeft = timeout.TimeLeft;
if (timeLeft <= TimeSpan.Zero || if (timeLeft <= TimeSpan.Zero ||
Expand All @@ -366,7 +374,7 @@ await Task.WhenAny(tcs.Task, Task.Delay(timeLeft, delayCancellationToken.Token))
} }
else else
{ {
using (cancellationToken.Register(() => tcs.SetCanceled())) using (cancellationToken.Register(s => ((TaskCompletionSource<NpgsqlConnector>)s).SetCanceled(), tcs))
await tcs.Task; await tcs.Task;
} }
} }
Expand Down Expand Up @@ -597,21 +605,23 @@ void CloseConnector(NpgsqlConnector connector, bool wasIdle)
} }
} }


void PruneIdleConnectors(object _) static void PruneIdleConnectors(object state)
{ {
var pool = (ConnectorPool)state;
var idle = pool._idle;
var now = DateTime.UtcNow; var now = DateTime.UtcNow;
var idleLifetime = Settings.ConnectionIdleLifetime; var idleLifetime = pool.Settings.ConnectionIdleLifetime;


for (var i = 0; i < _idle.Length; i++) for (var i = 0; i < idle.Length; i++)
{ {
if (State.Total <= _min) if (pool.State.Total <= pool._min)
return; return;


var connector = _idle[i]; var connector = idle[i];
if (connector == null || (now - connector.ReleaseTimestamp).TotalSeconds < idleLifetime) if (connector == null || (now - connector.ReleaseTimestamp).TotalSeconds < idleLifetime)
continue; continue;
if (Interlocked.CompareExchange(ref _idle[i], null, connector) == connector) if (Interlocked.CompareExchange(ref idle[i], null, connector) == connector)
CloseConnector(connector, true); pool.CloseConnector(connector, true);
} }
} }


Expand Down
8 changes: 1 addition & 7 deletions src/Npgsql/NameTranslation/INpgsqlNameTranslator.cs
@@ -1,10 +1,4 @@
using System; namespace Npgsql
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Npgsql
{ {
/// <summary> /// <summary>
/// A component which translates a CLR name (e.g. SomeClass) into a database name (e.g. some_class) /// A component which translates a CLR name (e.g. SomeClass) into a database name (e.g. some_class)
Expand Down
8 changes: 2 additions & 6 deletions src/Npgsql/NameTranslation/NpgsqlNullNameTranslator.cs
@@ -1,8 +1,4 @@
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;


namespace Npgsql.NameTranslation namespace Npgsql.NameTranslation
{ {
Expand All @@ -14,11 +10,11 @@ public class NpgsqlNullNameTranslator : INpgsqlNameTranslator
/// <summary> /// <summary>
/// Given a CLR type name (e.g class, struct, enum), translates its name to a database type name. /// Given a CLR type name (e.g class, struct, enum), translates its name to a database type name.
/// </summary> /// </summary>
public string TranslateTypeName(string clrName) => clrName; public string TranslateTypeName(string clrName) => clrName ?? throw new ArgumentNullException(nameof(clrName));


/// <summary> /// <summary>
/// Given a CLR member name (property or field), translates its name to a database type name. /// Given a CLR member name (property or field), translates its name to a database type name.
/// </summary> /// </summary>
public string TranslateMemberName(string clrName) => clrName; public string TranslateMemberName(string clrName) => clrName ?? throw new ArgumentNullException(nameof(clrName));
} }
} }
16 changes: 10 additions & 6 deletions src/Npgsql/NameTranslation/NpgsqlSnakeCaseNameTranslator.cs
Expand Up @@ -21,6 +21,7 @@
// TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. // TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
#endregion #endregion


using System;
using System.Linq; using System.Linq;
using System.Text; using System.Text;


Expand Down Expand Up @@ -54,9 +55,15 @@ public NpgsqlSnakeCaseNameTranslator(bool legacyMode)
/// <summary> /// <summary>
/// Given a CLR member name (property or field), translates its name to a database type name. /// Given a CLR member name (property or field), translates its name to a database type name.
/// </summary> /// </summary>
public string TranslateMemberName(string clrName) => LegacyMode public string TranslateMemberName(string clrName)
? string.Concat(clrName.Select((c, i) => i > 0 && char.IsUpper(c) ? "_" + c.ToString() : c.ToString())).ToLower() {
: ConvertToSnakeCase(clrName); if (clrName == null)
throw new ArgumentNullException(nameof(clrName));

return LegacyMode
? string.Concat(clrName.Select((c, i) => i > 0 && char.IsUpper(c) ? "_" + c.ToString() : c.ToString())).ToLower()
: ConvertToSnakeCase(clrName);
}


/// <summary> /// <summary>
/// Converts a string to its snake_case equivalent. /// Converts a string to its snake_case equivalent.
Expand All @@ -68,9 +75,6 @@ public NpgsqlSnakeCaseNameTranslator(bool legacyMode)
/// <param name="value">The value to convert.</param> /// <param name="value">The value to convert.</param>
public static string ConvertToSnakeCase(string value) public static string ConvertToSnakeCase(string value)
{ {
if (string.IsNullOrEmpty(value))
return value;

var sb = new StringBuilder(); var sb = new StringBuilder();
var state = SnakeCaseState.Start; var state = SnakeCaseState.Start;


Expand Down
2 changes: 1 addition & 1 deletion src/Npgsql/Npgsql.csproj
Expand Up @@ -6,7 +6,7 @@
<Copyright>Copyright 2019 © The Npgsql Development Team</Copyright> <Copyright>Copyright 2019 © The Npgsql Development Team</Copyright>
<Company>Npgsql</Company> <Company>Npgsql</Company>
<PackageTags>npgsql postgresql postgres ado ado.net database sql</PackageTags> <PackageTags>npgsql postgresql postgres ado ado.net database sql</PackageTags>
<VersionPrefix>4.0.7</VersionPrefix> <VersionPrefix>4.0.8</VersionPrefix>
<LangVersion>latest</LangVersion> <LangVersion>latest</LangVersion>
<TargetFrameworks>net45;net451;netstandard2.0</TargetFrameworks> <TargetFrameworks>net45;net451;netstandard2.0</TargetFrameworks>
<TargetFrameworks Condition="'$(OS)' != 'Windows_NT' OR '$(CoreOnly)' == 'True'">netstandard2.0</TargetFrameworks> <TargetFrameworks Condition="'$(OS)' != 'Windows_NT' OR '$(CoreOnly)' == 'True'">netstandard2.0</TargetFrameworks>
Expand Down
3 changes: 3 additions & 0 deletions src/Npgsql/NpgsqlConnection.cs
Expand Up @@ -1228,6 +1228,9 @@ public bool Wait(int timeout)
[PublicAPI] [PublicAPI]
public Task WaitAsync(CancellationToken cancellationToken) public Task WaitAsync(CancellationToken cancellationToken)
{ {
if (cancellationToken.IsCancellationRequested)
return PGUtil.CancelledTask;

CheckConnectionOpen(); CheckConnectionOpen();
Debug.Assert(Connector != null); Debug.Assert(Connector != null);
Log.Debug("Starting to wait asynchronously...", Connector.Id); Log.Debug("Starting to wait asynchronously...", Connector.Id);
Expand Down
20 changes: 13 additions & 7 deletions src/Npgsql/NpgsqlDataReader.cs
Expand Up @@ -441,7 +441,19 @@ async Task<bool> NextResult(bool async, bool isConsuming=false)
} }
} }


Expect<ParseCompleteMessage>(await Connector.ReadMessage(async)); try
{
Expect<ParseCompleteMessage>(await Connector.ReadMessage(async));
}
catch
{
// An exception occurred. Check if any statements we being prepared and revert our bookkeeping.
pStatement?.CompleteUnprepare();
throw;
}

pStatement?.CompletePrepare();

Expect<BindCompleteMessage>(await Connector.ReadMessage(async)); Expect<BindCompleteMessage>(await Connector.ReadMessage(async));
msg = await Connector.ReadMessage(async); msg = await Connector.ReadMessage(async);
switch (msg.Code) switch (msg.Code)
Expand All @@ -456,12 +468,6 @@ async Task<bool> NextResult(bool async, bool isConsuming=false)
default: default:
throw Connector.UnexpectedMessageReceived(msg.Code); throw Connector.UnexpectedMessageReceived(msg.Code);
} }

if (pStatement != null)
{
Debug.Assert(!pStatement.IsPrepared);
pStatement.CompletePrepare();
}
} }


// The following is a pretty awful hack to bring back output parameters for sequential readers (#2091) // The following is a pretty awful hack to bring back output parameters for sequential readers (#2091)
Expand Down
38 changes: 23 additions & 15 deletions src/Npgsql/PoolManager.cs
Expand Up @@ -40,39 +40,42 @@ static class PoolManager
internal const int InitialPoolsSize = 10; internal const int InitialPoolsSize = 10;


static readonly object _lock = new object(); static readonly object _lock = new object();
static (string Key, ConnectorPool Pool)[] _pools = new (string, ConnectorPool)[InitialPoolsSize]; static volatile (string Key, ConnectorPool Pool)[] _pools = new (string, ConnectorPool)[InitialPoolsSize];
static int _nextSlot; static volatile int _nextSlot;


internal static bool TryGetValue(string key, out ConnectorPool pool) internal static bool TryGetValue(string key, out ConnectorPool pool)
{ {
// Note that pools never get removed. _pools is strictly append-only. // Note that pools never get removed. _pools is strictly append-only.
var nextSlot = _nextSlot;
var pools = _pools; var pools = _pools;
var sw = new SpinWait(); var sw = new SpinWait();


// First scan the pools and do reference equality on the connection strings // First scan the pools and do reference equality on the connection strings
for (var i = 0; i < _nextSlot; i++) for (var i = 0; i < nextSlot; i++)
{ {
if (ReferenceEquals(pools[i].Key, key)) var cp = pools[i];
if (ReferenceEquals(cp.Key, key))
{ {
// It's possible that this pool entry is currently being written: the connection string // It's possible that this pool entry is currently being written: the connection string
// component has already been writte, but the pool component is just about to be. So we // component has already been writte, but the pool component is just about to be. So we
// loop on the pool until it's non-null // loop on the pool until it's non-null
while (Volatile.Read(ref pools[i].Pool) == null) while (Volatile.Read(ref cp.Pool) == null)
sw.SpinOnce(); sw.SpinOnce();
pool = pools[i].Pool; pool = cp.Pool;
return true; return true;
} }
} }


// Next try value comparison on the strings // Next try value comparison on the strings
for (var i = 0; i < _nextSlot; i++) for (var i = 0; i < nextSlot; i++)
{ {
if (pools[i].Key == key) var cp = pools[i];
if (cp.Key == key)
{ {
// See comment above // See comment above
while (Volatile.Read(ref pools[i].Pool) == null) while (Volatile.Read(ref cp.Pool) == null)
sw.SpinOnce(); sw.SpinOnce();
pool = pools[i].Pool; pool = cp.Pool;
return true; return true;
} }
} }
Expand All @@ -93,7 +96,7 @@ internal static ConnectorPool GetOrAdd(string key, ConnectorPool pool)
{ {
var newPools = new (string, ConnectorPool)[_pools.Length * 2]; var newPools = new (string, ConnectorPool)[_pools.Length * 2];
Array.Copy(_pools, newPools, _pools.Length); Array.Copy(_pools, newPools, _pools.Length);
Interlocked.Exchange(ref _pools, newPools); _pools = newPools;
} }


_pools[_nextSlot].Key = key; _pools[_nextSlot].Key = key;
Expand All @@ -113,11 +116,16 @@ internal static void Clear(string connString)


internal static void ClearAll() internal static void ClearAll()
{ {
for (var i = 0; i < _nextSlot; i++) lock (_lock)
{ {
if (_pools[i].Key == null) var pools = _pools;
return; for (var i = 0; i < _nextSlot; i++)
_pools[i].Pool?.Clear(); {
var cp = pools[i];
if (cp.Key == null)
return;
cp.Pool?.Clear();
}
} }
} }


Expand Down
7 changes: 3 additions & 4 deletions src/Npgsql/PreparedStatement.cs
Expand Up @@ -144,15 +144,14 @@ enum PreparedState


/// <summary> /// <summary>
/// The statement has been selected for preparation, but the preparation hasn't started yet. /// The statement has been selected for preparation, but the preparation hasn't started yet.
/// This is a temporary state that only occurs during preparation. /// This is a temporary state that only occurs during preparation, and indicates that no
/// Specifically, no protocol message (Parse) has been sent yet. Specifically, it means that /// no protocol message (Parse) has been sent yet.
/// a Parse message for the statement has already been written to the write buffer.
/// </summary> /// </summary>
ToBePrepared, ToBePrepared,


/// <summary> /// <summary>
/// The statement is in the process of being prepared. This is a temporary state that only occurs during /// The statement is in the process of being prepared. This is a temporary state that only occurs during
/// preparation. Specifically, it means that a Parse message for the statement has already been written /// preparation, and indicates that a Parse protocol message for the statement has already been written
/// to the write buffer. /// to the write buffer.
/// </summary> /// </summary>
BeingPrepared, BeingPrepared,
Expand Down

0 comments on commit 9c1a1d5

Please sign in to comment.