Bläddra i källkod

More standard connection handling + no custom pooling for ADO (#7230)

* More standard connection handling + no custom pooling for ADO

* Using unixODBC-2.3.9

* Same connection string as aspnetcore

* Previous Npgsql version

Co-authored-by: LLT21 <[email protected]>
LLT21 3 år sedan
förälder
incheckning
4d03083f8b

+ 22 - 22
frameworks/CSharp/appmpower/appmpower-odbc-pg.dockerfile

@@ -8,20 +8,20 @@ RUN apt-get install -y make build-essential libssl-dev zlib1g-dev libbz2-dev \
 WORKDIR /odbc
 
 # To compile the latest postgresql odbc driver, postgresql itself needs to be installed
-RUN curl -L -o postgresql-14.1.tar.gz https://ftp.postgresql.org/pub/source/v14.1/postgresql-14.1.tar.gz
+#RUN curl -L -o postgresql-14.1.tar.gz https://ftp.postgresql.org/pub/source/v14.1/postgresql-14.1.tar.gz
 RUN curl -L -o unixODBC-2.3.9.tar.gz ftp://ftp.unixodbc.org/pub/unixODBC/unixODBC-2.3.9.tar.gz
-RUN curl -L -o psqlodbc-13.02.0000.tar.gz https://ftp.postgresql.org/pub/odbc/versions/src/psqlodbc-13.02.0000.tar.gz
+#RUN curl -L -o psqlodbc-13.02.0000.tar.gz https://ftp.postgresql.org/pub/odbc/versions/src/psqlodbc-13.02.0000.tar.gz
 
-RUN tar -xvf postgresql-14.1.tar.gz
+#RUN tar -xvf postgresql-14.1.tar.gz
 RUN tar -xvf unixODBC-2.3.9.tar.gz
-RUN tar -xvf psqlodbc-13.02.0000.tar.gz
+#RUN tar -xvf psqlodbc-13.02.0000.tar.gz
 
-WORKDIR /odbc/postgresql-14.1
-RUN ./configure
-RUN make
-RUN make install
+#WORKDIR /odbc/postgresql-14.1
+#RUN ./configure
+#RUN make
+#RUN make install
 
-ENV PATH=/usr/local/pgsql/bin:$PATH
+#ENV PATH=/usr/local/pgsql/bin:$PATH
 
 WORKDIR /odbc/unixODBC-2.3.9
 RUN ./configure --prefix=/usr/local/unixODBC
@@ -30,10 +30,10 @@ RUN make install
 
 ENV PATH=/usr/local/unixODBC/lib:$PATH
 
-WORKDIR /odbc/psqlodbc-13.02.0000
-RUN ./configure --with-unixodbc=/usr/local/unixODBC --with-libpq=/usr/local/pgsql --prefix=/usr/local/pgsqlodbc
-RUN make
-RUN make install
+#WORKDIR /odbc/psqlodbc-13.02.0000
+#RUN ./configure --with-unixodbc=/usr/local/unixODBC --with-libpq=/usr/local/pgsql --prefix=/usr/local/pgsqlodbc
+#RUN make
+#RUN make install
 
 WORKDIR /app
 COPY src .
@@ -44,19 +44,19 @@ FROM mcr.microsoft.com/dotnet/aspnet:6.0.0 AS runtime
 
 RUN apt-get update
 # The following installs standard versions unixodbc 2.3.6 and pgsqlodbc 11
-#RUN apt-get install -y unixodbc odbc-postgresql
+RUN apt-get install -y unixodbc odbc-postgresql
 # unixodbc still needs to be installed even if compiled locally
-RUN apt-get install -y unixodbc wget curl libpq-dev build-essential
+#RUN apt-get install -y unixodbc wget curl libpq-dev build-essential
 
 WORKDIR /odbc
 
-RUN curl -L -o pgpool-II-4.2.3.tar.gz https://www.pgpool.net/mediawiki/download.php?f=pgpool-II-4.2.3.tar.gz
-RUN tar -xvf pgpool-II-4.2.3.tar.gz
+#RUN curl -L -o pgpool-II-4.2.3.tar.gz https://www.pgpool.net/mediawiki/download.php?f=pgpool-II-4.2.3.tar.gz
+#RUN tar -xvf pgpool-II-4.2.3.tar.gz
 
-WORKDIR /odbc/pgpool-II-4.2.3
-RUN ./configure
-RUN make
-RUN make install
+#WORKDIR /odbc/pgpool-II-4.2.3
+#RUN ./configure
+#RUN make
+#RUN make install
 
 COPY --from=build /usr/local/unixODBC /usr/local/unixODBC
 
@@ -66,7 +66,7 @@ COPY --from=build /usr/local/unixODBC /usr/local/unixODBC
 
 ENV PATH=/usr/local/unixODBC/bin:$PATH
 
-COPY --from=build /usr/local/pgsqlodbc /usr/local/pgsqlodbc
+#COPY --from=build /usr/local/pgsqlodbc /usr/local/pgsqlodbc
 
 WORKDIR /etc/
 COPY odbcinst.ini .

+ 2 - 2
frameworks/CSharp/appmpower/odbcinst.ini

@@ -16,8 +16,8 @@ Description=ODBC for PostgreSQL
 ; in version 08.x. Note that the library can also be installed under an other
 ; path than /usr/local/lib/ following your installation.
 ; This is the standard location used by apt-get install -y unixodbc
-;Driver = /usr/lib/x86_64-linux-gnu/odbc/psqlodbcw.so
-Driver =/usr/local/pgsqlodbc/lib/psqlodbcw.so
+Driver = /usr/lib/x86_64-linux-gnu/odbc/psqlodbcw.so
+;Driver =/usr/local/pgsqlodbc/lib/psqlodbcw.so
 Threading = 0
 CPTimeout = 0
 

+ 2 - 2
frameworks/CSharp/appmpower/src/Db/DataProvider.cs

@@ -5,8 +5,8 @@ namespace appMpower.Db
 #if MYSQL
       public const string ConnectionString = "Driver={MariaDB};Server=tfb-database;Database=hello_world;Uid=benchmarkdbuser;Pwd=benchmarkdbpass;Pooling=false;OPTIONS=67108864;FLAG_FORWARD_CURSOR=1"; 
 #elif ADO
-      public const string ConnectionString = "Server=tfb-database;Database=hello_world;User Id=benchmarkdbuser;Password=benchmarkdbpass;SSL Mode=Disable;Maximum Pool Size=8;NoResetOnClose=true;Enlist=false;Max Auto Prepare=4;Multiplexing=true;Write Coalescing Buffer Threshold Bytes=1000";
-      //public const string ConnectionString = "Server=localhost;Database=hello_world;User Id=benchmarkdbuser;Password=benchmarkdbpass;SSL Mode=Disable;Maximum Pool Size=9;NoResetOnClose=true;Enlist=false;Max Auto Prepare=4;Multiplexing=true;Write Coalescing Buffer Threshold Bytes=1000";
+      public const string ConnectionString = "Server=tfb-database;Database=hello_world;User Id=benchmarkdbuser;Password=benchmarkdbpass;SSL Mode=Disable;Maximum Pool Size=18;Enlist=false;Max Auto Prepare=4;Multiplexing=true;Write Coalescing Buffer Threshold Bytes=1000";
+      //public const string ConnectionString = "Server=localhost;Database=hello_world;User Id=benchmarkdbuser;Password=benchmarkdbpass;SSL Mode=Disable;Maximum Pool Size=18;Enlist=false;Max Auto Prepare=4;Multiplexing=true;Write Coalescing Buffer Threshold Bytes=1000";
 #else
       public const string ConnectionString = "Driver={PostgreSQL};Server=tfb-database;Database=hello_world;Uid=benchmarkdbuser;Pwd=benchmarkdbpass;UseServerSidePrepare=1;Pooling=false";
       //public const string ConnectionString = "Driver={PostgreSQL};Server=localhost;Database=hello_world;Uid=benchmarkdbuser;Pwd=benchmarkdbpass;UseServerSidePrepare=1;Pooling=false";

+ 16 - 0
frameworks/CSharp/appmpower/src/Db/InternalConnection.cs

@@ -0,0 +1,16 @@
+using System.Collections.Concurrent;
+using System.Data;
+
+namespace appMpower.Db
+{
+   public class InternalConnection : System.IDisposable
+   {
+      public short Number { get; set; }
+      public IDbConnection DbConnection { get; set; }
+      public ConcurrentDictionary<string, PooledCommand> PooledCommands { get; set; }
+
+      public void Dispose()
+      {
+      }
+   }
+}

+ 20 - 9
frameworks/CSharp/appmpower/src/Db/PooledCommand.cs

@@ -1,5 +1,4 @@
 using System.Data;
-using System.Data.Common;
 using System.Threading.Tasks;
 
 namespace appMpower.Db
@@ -17,7 +16,12 @@ namespace appMpower.Db
 
       public PooledCommand(string commandText, PooledConnection pooledConnection)
       {
-         pooledConnection.GetCommand(commandText, this);
+         pooledConnection.GetCommand(commandText, CommandType.Text, this);
+      }
+
+      public PooledCommand(string commandText, CommandType commandType, PooledConnection pooledConnection)
+      {
+         pooledConnection.GetCommand(commandText, commandType, this);
       }
 
       internal PooledCommand(IDbCommand dbCommand, PooledConnection pooledConnection)
@@ -143,6 +147,11 @@ namespace appMpower.Db
          return _dbCommand.CreateParameter();
       }
 
+      public IDbDataParameter CreateParameter(string name, object value)
+      {
+         return CreateParameter(name, DbType.String, value);
+      }
+
       public IDbDataParameter CreateParameter(string name, DbType dbType, object value)
       {
          IDbDataParameter dbDataParameter = null;
@@ -177,12 +186,12 @@ namespace appMpower.Db
 
       public async Task<int> ExecuteNonQueryAsync()
       {
-         return await (_dbCommand as DbCommand).ExecuteNonQueryAsync();
+         return await (_dbCommand as System.Data.Common.DbCommand).ExecuteNonQueryAsync();
       }
 
-      public async Task<DbDataReader> ExecuteReaderAsync(CommandBehavior behavior)
+      public async Task<System.Data.Common.DbDataReader> ExecuteReaderAsync(CommandBehavior behavior)
       {
-         return await (_dbCommand as DbCommand).ExecuteReaderAsync(behavior);
+         return await (_dbCommand as System.Data.Common.DbCommand).ExecuteReaderAsync(behavior);
       }
 
       public IDataReader ExecuteReader(CommandBehavior behavior)
@@ -197,14 +206,16 @@ namespace appMpower.Db
       }
 #nullable disable
 
-      public void Prepare()
+#nullable enable
+      public async Task<object?> ExecuteScalarAsync()
       {
-         _dbCommand.Prepare();
+         return await ((System.Data.Common.DbCommand)_dbCommand).ExecuteScalarAsync();
       }
+#nullable disable
 
-      public void Release()
+      public void Prepare()
       {
-         _pooledConnection.ReleaseCommand(this);
+         _dbCommand.Prepare();
       }
 
       public void Dispose()

+ 34 - 37
frameworks/CSharp/appmpower/src/Db/PooledConnection.cs

@@ -1,25 +1,19 @@
 using System.Collections.Concurrent;
 using System.Data;
-using System.Data.Common;
 using System.Threading.Tasks;
 
 namespace appMpower.Db
 {
    public class PooledConnection : IDbConnection
    {
-      private bool _released = false;
       private short _number = 0;
+      private string _connectionString;
       private IDbConnection _dbConnection;
       private ConcurrentDictionary<string, PooledCommand> _pooledCommands;
 
-      internal PooledConnection()
+      public PooledConnection(string connectionString)
       {
-      }
-
-      internal PooledConnection(IDbConnection dbConnection)
-      {
-         _dbConnection = dbConnection;
-         _pooledCommands = new ConcurrentDictionary<string, PooledCommand>();
+         _connectionString = connectionString;
       }
 
       internal ConcurrentDictionary<string, PooledCommand> PooledCommands
@@ -90,22 +84,11 @@ namespace appMpower.Db
       {
          get
          {
+            if (_dbConnection is null) return ConnectionState.Closed;
             return _dbConnection.State;
          }
       }
 
-      public bool Released
-      {
-         get
-         {
-            return _released;
-         }
-         internal set
-         {
-            _released = value;
-         }
-      }
-
       public IDbTransaction BeginTransaction()
       {
          return _dbConnection.BeginTransaction();
@@ -124,7 +107,11 @@ namespace appMpower.Db
       public void Close()
       {
          _dbConnection.Close();
-         _released = true;
+      }
+
+      public async Task CloseAsync()
+      {
+         await (_dbConnection as System.Data.Common.DbConnection).CloseAsync();
       }
 
       public IDbCommand CreateCommand()
@@ -140,32 +127,40 @@ namespace appMpower.Db
          }
       }
 
-      public void Release()
+      public void Dispose()
       {
-         if (!_released && _dbConnection.State == ConnectionState.Open)
-         {
-            PooledConnections.Release(this);
-         }
+         PooledConnections.Dispose(this);
       }
 
-      public void Dispose()
+      public async Task OpenAsync()
       {
-         if (!_released && _dbConnection.State == ConnectionState.Open)
+#if ADO
+         _dbConnection = new Npgsql.NpgsqlConnection(_connectionString);
+#else
+         if (_dbConnection is null)
          {
-            PooledConnections.Dispose(this);
+            using var internalConnection = await PooledConnections.GetConnection(_connectionString);
+
+            _dbConnection = internalConnection.DbConnection;
+            _number = internalConnection.Number;
+            _pooledCommands = internalConnection.PooledCommands;
          }
-      }
+#endif
 
-      public async Task OpenAsync()
-      {
          if (_dbConnection.State == ConnectionState.Closed)
          {
-            await (_dbConnection as DbConnection).OpenAsync();
+            await (_dbConnection as System.Data.Common.DbConnection).OpenAsync();
          }
       }
 
-      internal PooledCommand GetCommand(string commandText, PooledCommand pooledCommand)
+      internal PooledCommand GetCommand(string commandText, CommandType commandType, PooledCommand pooledCommand)
       {
+#if ADO
+         pooledCommand.DbCommand = this.DbConnection.CreateCommand();
+         pooledCommand.DbCommand.CommandText = commandText;
+         pooledCommand.DbCommand.CommandType = commandType;
+         pooledCommand.PooledConnection = this;
+#else
          PooledCommand internalCommand;
 
          if (_pooledCommands.TryRemove(commandText, out internalCommand))
@@ -177,22 +172,24 @@ namespace appMpower.Db
          {
             pooledCommand.DbCommand = this.DbConnection.CreateCommand();
             pooledCommand.DbCommand.CommandText = commandText;
+            pooledCommand.DbCommand.CommandType = commandType;
             pooledCommand.PooledConnection = this;
 
             //For non odbc drivers like Npgsql which do not support Prepare
-#if !ADO
             pooledCommand.DbCommand.Prepare();
-#endif            
 
             //Console.WriteLine("prepare pool connection: " + this._number + " for command " + _pooledCommands.Count);
          }
+#endif
 
          return pooledCommand;
       }
 
       public void ReleaseCommand(PooledCommand pooledCommand)
       {
+#if !ADO
          _pooledCommands.TryAdd(pooledCommand.CommandText, pooledCommand);
+#endif
       }
    }
 }

+ 24 - 29
frameworks/CSharp/appmpower/src/Db/PooledConnections.cs

@@ -9,51 +9,47 @@ namespace appMpower.Db
       private static short _createdConnections = 0;
       private static short _maxConnections = 240;
 
-      private static ConcurrentStack<PooledConnection> _stack = new ConcurrentStack<PooledConnection>();
-      private static ConcurrentQueue<TaskCompletionSource<PooledConnection>> _waitingQueue = new ConcurrentQueue<TaskCompletionSource<PooledConnection>>();
+      private static ConcurrentStack<InternalConnection> _stack = new();
+      private static ConcurrentQueue<TaskCompletionSource<InternalConnection>> _waitingQueue = new();
 
-      public static async Task<PooledConnection> GetConnection(string connectionString)
+      public static async Task<InternalConnection> GetConnection(string connectionString)
       {
-         PooledConnection pooledConnection = null;
+         InternalConnection internalConnection = null;
 
          if (_connectionsCreated)
          {
-            if (_stack.TryPop(out pooledConnection))
+            if (!_stack.TryPop(out internalConnection))
             {
-               pooledConnection.Released = false;
-            }
-            else
-            {
-               pooledConnection = await GetPooledConnectionAsync();
+               internalConnection = await GetPooledConnectionAsync();
             }
 
-            return pooledConnection;
+            return internalConnection;
          }
          else
          {
-            pooledConnection = new PooledConnection();
+            internalConnection = new InternalConnection();
 
 #if ADO
-            pooledConnection.DbConnection = new Npgsql.NpgsqlConnection(connectionString);
+            internalConnection.DbConnection = new Npgsql.NpgsqlConnection(connectionString);
 #else
-            pooledConnection.DbConnection = new System.Data.Odbc.OdbcConnection(connectionString);
+            internalConnection.DbConnection = new System.Data.Odbc.OdbcConnection(connectionString);
 #endif               
 
             _createdConnections++;
 
             if (_createdConnections == _maxConnections) _connectionsCreated = true;
 
-            pooledConnection.Number = _createdConnections;
-            pooledConnection.PooledCommands = new ConcurrentDictionary<string, PooledCommand>();
+            internalConnection.Number = _createdConnections;
+            internalConnection.PooledCommands = new ConcurrentDictionary<string, PooledCommand>();
             //Console.WriteLine("opened connection number: " + pooledConnection.Number);
 
-            return pooledConnection;
+            return internalConnection;
          }
       }
 
-      public static Task<PooledConnection> GetPooledConnectionAsync()
+      public static Task<InternalConnection> GetPooledConnectionAsync()
       {
-         var taskCompletionSource = new TaskCompletionSource<PooledConnection>(TaskCreationOptions.RunContinuationsAsynchronously);
+         var taskCompletionSource = new TaskCompletionSource<InternalConnection>(TaskCreationOptions.RunContinuationsAsynchronously);
 
          _waitingQueue.Enqueue(taskCompletionSource);
          return taskCompletionSource.Task;
@@ -61,27 +57,26 @@ namespace appMpower.Db
 
       public static void Dispose(PooledConnection pooledConnection)
       {
-         PooledConnection newPooledConnection = new PooledConnection();
+         InternalConnection internalConnection = new InternalConnection();
 
-         newPooledConnection.DbConnection = pooledConnection.DbConnection;
-         newPooledConnection.Number = pooledConnection.Number;
-         newPooledConnection.PooledCommands = pooledConnection.PooledCommands;
+         internalConnection.DbConnection = pooledConnection.DbConnection;
+         internalConnection.Number = pooledConnection.Number;
+         internalConnection.PooledCommands = pooledConnection.PooledCommands;
 
-         Release(newPooledConnection);
+         Release(internalConnection);
       }
 
-      public static void Release(PooledConnection pooledConnection)
+      public static void Release(InternalConnection internalConnection)
       {
-         TaskCompletionSource<PooledConnection> taskCompletionSource;
+         TaskCompletionSource<InternalConnection> taskCompletionSource;
 
          if (_waitingQueue.TryDequeue(out taskCompletionSource))
          {
-            taskCompletionSource.SetResult(pooledConnection);
+            taskCompletionSource.SetResult(internalConnection);
          }
          else
          {
-            pooledConnection.Released = true;
-            _stack.Push(pooledConnection);
+            _stack.Push(internalConnection);
          }
       }
    }

+ 44 - 52
frameworks/CSharp/appmpower/src/RawDb.cs

@@ -32,36 +32,37 @@ namespace appMpower
 
       public static async Task<World> LoadSingleQueryRow()
       {
-         var pooledConnection = await PooledConnections.GetConnection(DataProvider.ConnectionString);
-         pooledConnection.Open();
+         using var pooledConnection = new PooledConnection(DataProvider.ConnectionString);
+         await pooledConnection.OpenAsync();
 
          var (pooledCommand, _) = CreateReadCommand(pooledConnection);
-         var world = await ReadSingleRow(pooledCommand);
 
-         pooledCommand.Release();
-         pooledConnection.Release();
+         using (pooledCommand)
+         {
+            var world = await ReadSingleRow(pooledCommand);
 
-         return world;
+            return world;
+         }
       }
 
       public static async Task<World[]> LoadMultipleQueriesRows(int count)
       {
          var worlds = new World[count];
 
-         var pooledConnection = await PooledConnections.GetConnection(DataProvider.ConnectionString);
-         pooledConnection.Open();
+         using var pooledConnection = new PooledConnection(DataProvider.ConnectionString);
+         await pooledConnection.OpenAsync();
 
          var (pooledCommand, dbDataParameter) = CreateReadCommand(pooledConnection);
 
-         for (int i = 0; i < count; i++)
+         using (pooledCommand)
          {
-            worlds[i] = await ReadSingleRow(pooledCommand);
-            dbDataParameter.Value = _random.Next(1, 10001);
+            for (int i = 0; i < count; i++)
+            {
+               worlds[i] = await ReadSingleRow(pooledCommand);
+               dbDataParameter.Value = _random.Next(1, 10001);
+            }
          }
 
-         pooledCommand.Release();
-         pooledConnection.Release();
-
          return worlds;
       }
 
@@ -69,17 +70,20 @@ namespace appMpower
       {
          var fortunes = new List<Fortune>();
 
-         var pooledConnection = await PooledConnections.GetConnection(DataProvider.ConnectionString);
-         pooledConnection.Open();
+         using var pooledConnection = new PooledConnection(DataProvider.ConnectionString);
+         await pooledConnection.OpenAsync();
 
          var pooledCommand = new PooledCommand("SELECT * FROM fortune", pooledConnection);
-         var dataReader = await pooledCommand.ExecuteReaderAsync(CommandBehavior.SingleResult & CommandBehavior.SequentialAccess);
 
-         while (dataReader.Read())
+         using (pooledCommand)
          {
-            fortunes.Add(new Fortune
-            (
-                id: dataReader.GetInt32(0),
+            var dataReader = await pooledCommand.ExecuteReaderAsync(CommandBehavior.SingleResult & CommandBehavior.SequentialAccess);
+
+            while (dataReader.Read())
+            {
+               fortunes.Add(new Fortune
+               (
+                   id: dataReader.GetInt32(0),
 #if MYSQL
                //MariaDB ODBC connector does not correctly support Japanese characters in combination with default ADO.NET;
                //as a solution we custom read this string
@@ -88,11 +92,10 @@ namespace appMpower
                 message: dataReader.GetString(1)
 #endif
             ));
-         }
+            }
 
-         dataReader.Close();
-         pooledCommand.Release();
-         pooledConnection.Release();
+            dataReader.Close();
+         }
 
          fortunes.Add(new Fortune(id: 0, message: "Additional fortune added at request time."));
          fortunes.Sort();
@@ -104,20 +107,21 @@ namespace appMpower
       {
          var worlds = new World[count];
 
-         var pooledConnection = await PooledConnections.GetConnection(DataProvider.ConnectionString);
-         pooledConnection.Open();
+         using var pooledConnection = new PooledConnection(DataProvider.ConnectionString);
+         await pooledConnection.OpenAsync();
 
          var (queryCommand, dbDataParameter) = CreateReadCommand(pooledConnection);
 
-         for (int i = 0; i < count; i++)
+         using (queryCommand)
          {
-            worlds[i] = await ReadSingleRow(queryCommand);
-            dbDataParameter.Value = _random.Next(1, 10001);
+            for (int i = 0; i < count; i++)
+            {
+               worlds[i] = await ReadSingleRow(queryCommand);
+               dbDataParameter.Value = _random.Next(1, 10001);
+            }
          }
 
-         queryCommand.Release();
-
-         var updateCommand = new PooledCommand(PlatformBenchmarks.BatchUpdateString.Query(count), pooledConnection);
+         using var updateCommand = new PooledCommand(PlatformBenchmarks.BatchUpdateString.Query(count), pooledConnection);
 
          var ids = PlatformBenchmarks.BatchUpdateString.Ids;
          var randoms = PlatformBenchmarks.BatchUpdateString.Randoms;
@@ -145,9 +149,6 @@ namespace appMpower
 
          await updateCommand.ExecuteNonQueryAsync();
 
-         updateCommand.Release();
-         pooledConnection.Release();
-
          return worlds;
       }
 
@@ -202,10 +203,10 @@ namespace appMpower
             queryString = _queriesMultipleRows[count] = PlatformBenchmarks.StringBuilderCache.GetStringAndRelease(stringBuilder);
          }
 
-         var pooledConnection = await PooledConnections.GetConnection(DataProvider.ConnectionString);
-         pooledConnection.Open();
+         using var pooledConnection = new PooledConnection(DataProvider.ConnectionString);
+         await pooledConnection.OpenAsync();
 
-         var pooledCommand = new PooledCommand(queryString, pooledConnection);
+         using var pooledCommand = new PooledCommand(queryString, pooledConnection);
 
          for (int i = 0; i < count; i++)
          {
@@ -228,8 +229,6 @@ namespace appMpower
          } while (await dataReader.NextResultAsync());
 
          dataReader.Close();
-         pooledCommand.Release();
-         pooledConnection.Release();
 
          return worlds;
       }
@@ -254,8 +253,8 @@ namespace appMpower
 
       public static async Task PopulateCache()
       {
-         var pooledConnection = await PooledConnections.GetConnection(DataProvider.ConnectionString);
-         pooledConnection.Open();
+         using var pooledConnection = new PooledConnection(DataProvider.ConnectionString);
+         await pooledConnection.OpenAsync();
 
          var (pooledCommand, dbDataParameter) = CreateReadCommand(pooledConnection);
 
@@ -270,9 +269,6 @@ namespace appMpower
                cache.Set<CachedWorld>(cacheKeys[i], await ReadSingleRow(pooledCommand));
             }
          }
-
-         pooledCommand.Release();
-         pooledConnection.Release();
       }
 
       public static Task<CachedWorld[]> LoadCachedQueries(int count)
@@ -301,11 +297,10 @@ namespace appMpower
          return Task.FromResult(result);
       }
 
-      //static async Task<CachedWorld[]> LoadUncachedQueries(int id, int i, int count, RawDb rawdb, CachedWorld[] result)
       static async Task<CachedWorld[]> LoadUncachedQueries(int id, int i, int count, CachedWorld[] result)
       {
-         var pooledConnection = await PooledConnections.GetConnection(DataProvider.ConnectionString);
-         pooledConnection.Open();
+         using var pooledConnection = new PooledConnection(DataProvider.ConnectionString);
+         await pooledConnection.OpenAsync();
 
          var (pooledCommand, dbDataParameter) = CreateReadCommand(pooledConnection);
 
@@ -329,9 +324,6 @@ namespace appMpower
                dbDataParameter.Value = id;
                key = cacheKeys[id];
             }
-
-            pooledCommand.Release();
-            pooledConnection.Release();
          }
 
          return result;