Остановка пула соединений Npgsql при соединениях MinPoolSize
Первый раз работал с Npgsql, хотя я занимался другим программированием на PostgreSQL. Npgsql 3.1.6, PostgreSQL 9.5. Visual Studio 2015 с.Net 4.5.1.
У меня есть строка подключения, которая выглядит следующим образом (одна и та же строка используется каждый раз, без изменений, для каждой попытки подключения к БД):
Сервер =dbserver;SearchPath= сеть; База данных =netinfo; ID пользователя =netuser; Пароль =netpassword; Порт =19491;CommandTimeout=300; Пул =true;MaxPoolSize=75
Это многопоточный сборщик данных C# для нашей сети. До 32 потоков работает на коллекторе. Каждый поток открывает соединение при необходимости, но одновременно использует только одно соединение. Соединение будет закрыто и повторно открыто потоком, если это необходимо. Я написал свой собственный пул соединений, и он работал; откройте связку в начале, вытащите открытое соединение из ConcurrentQueue
, используйте его, а затем верните в очередь. В очереди проведено 16 открытых соединений. Чревато опасностью, если не сделано правильно, но это сработало. Во время проверки кода коллега включил меня в пул соединений Npgsql, поэтому я пытаюсь его использовать.
я собираюсь System.InvalidOperationException
, "The connection is not open"
когда я достигну команды ОБНОВИТЬ (dbCommand.ExecuteNonQuery());
Я не верю, что сама команда важна - это только та, которую она поражает. Я замечаю, что на сервере БД netstat показывает MinPoolSize+1 открытый сокет. В приведенной выше строке подключения он не определен, поэтому MinPoolSize равен 1. Я вижу два сокета в netstat. Если я установлю MinPoolSize на 16, я увижу 17 сокетов. Похоже, Npgsql открывает минимальный размер пула, а затем создает исключение InvalidOperationException при следующем подключении. Но он должен иметь до 75 доступных соединений и блокировать, когда они недоступны. Это не.
Максимальное количество соединений на моем сервере PostgreSQL составляет 100; Я не близко к этому порогу.
Это работает, когда я использую свой самописанный метод совместного использования пула, поэтому нет проблем с кодом, который выполняет запросы. Это просто, как я получаю текущее соединение.
Мысли? В поле зрения? Спасибо!
Изменить: согласно запросу.,, это немного долго, но это показывает пару смежных условных обозначений для идеи потока.
lock (ArpTableLocks.GetLock(nd.IdNd + " " + idMi + " " + idIf))
{
if (_arpTableList.Get(nd.IdNd, idMi, idIf) == null)
{
// No device/MAC/IP/intf entry in DB, add one
var dbConn = new NpgsqlConnection(DBStrings.connectionString);
var dbCommand = new NpgsqlCommand(DBStrings.sqlARPTableInsert, dbConn);
dbCommand.Parameters.Add(new NpgsqlParameter("@id_mi", NpgsqlTypes.NpgsqlDbType.Integer, 4));
dbCommand.Parameters.Add(new NpgsqlParameter("@id_nd", NpgsqlTypes.NpgsqlDbType.Integer, 4));
dbCommand.Parameters.Add(new NpgsqlParameter("@id_if", NpgsqlTypes.NpgsqlDbType.Integer, 4));
dbCommand.Parameters["@id_mi"].Value = idMi.ToString();
dbCommand.Parameters["@id_nd"].Value = nd.IdNd.ToString();
dbCommand.Parameters["@id_if"].Value = idIf.ToString();
var dbRead = dbCommand.ExecuteReader();
dbRead.Read();
idAt = dbRead.GetInt32(0);
var arpTableListEntry = new ArpTableEntry
{
Id = idAt,
IdNd = nd.IdNd,
IdMi = idMi,
IdIf = idIf
};
_arpTableList.Add(arpTableListEntry);
dbRead.Close();
dbConn.Close();
}
}
idAt = (_arpTableList.Get(nd.IdNd, idMi, idIf).Id);
lock (ActiveArpTableLocks.GetLock(nd.IdV + " " + idAt))
{
if (_activeArpTableList.Get(nd.IdV, idAt) == null)
{
var dbConn = new NpgsqlConnection(DBStrings.connectionString);
NpgsqlCommand dbCommand = new NpgsqlCommand(DBStrings.sqlActiveARPTableInsert, dbConn);
dbCommand.Parameters.Add(new NpgsqlParameter("@id_v", NpgsqlTypes.NpgsqlDbType.Integer, 4));
dbCommand.Parameters.Add(new NpgsqlParameter("@id_at", NpgsqlTypes.NpgsqlDbType.Integer, 4));
dbCommand.Parameters.Add(new NpgsqlParameter("@seen", NpgsqlTypes.NpgsqlDbType.Timestamp));
dbCommand.Parameters["@id_v"].Value = nd.IdV.ToString();
dbCommand.Parameters["@id_at"].Value = idAt.ToString();
dbCommand.Parameters["@seen"].Value = ae.TimeSeen;
dbCommand.ExecuteNonQuery();
// Insert a history record
dbCommand = new NpgsqlCommand(DBStrings.sqlHistoryARPTableInsert, dbConn);
dbCommand.Parameters.Add(new NpgsqlParameter("@id_v", NpgsqlTypes.NpgsqlDbType.Integer, 4));
dbCommand.Parameters.Add(new NpgsqlParameter("@id_at", NpgsqlTypes.NpgsqlDbType.Integer, 4));
dbCommand.Parameters.Add(new NpgsqlParameter("@firstseen", NpgsqlTypes.NpgsqlDbType.Timestamp));
dbCommand.Parameters["@id_v"].Value = nd.IdV.ToString();
dbCommand.Parameters["@id_at"].Value = idAt.ToString();
dbCommand.Parameters["@firstseen"].Value = ae.TimeSeen;
dbCommand.ExecuteNonQuery(); // Exception thrown here
dbConn.Close();
Interlocked.Increment(ref _arpEntryAdded);
}
else
{
// DB has an active ARP table entry, so update its seen time.
var dbConn = new NpgsqlConnection(DBStrings.connectionString);
NpgsqlCommand dbCommand = new NpgsqlCommand(DBStrings.sqlActiveARPTableUpdateSeen, dbConn);
dbCommand.Parameters.Add(new NpgsqlParameter("@seen", NpgsqlTypes.NpgsqlDbType.Timestamp));
dbCommand.Parameters.Add(new NpgsqlParameter("@id_v", NpgsqlTypes.NpgsqlDbType.Integer, 4));
dbCommand.Parameters.Add(new NpgsqlParameter("@id_at", NpgsqlTypes.NpgsqlDbType.Integer, 4));
dbCommand.Parameters["@seen"].Value = ae.TimeSeen;
dbCommand.Parameters["@id_v"].Value = nd.IdV.ToString();
dbCommand.Parameters["@id_at"].Value = idAt.ToString();
dbCommand.ExecuteNonQuery();
dbConn.Close();
// Remove from activearptable hashtable
_activeArpTableList.Delete(nd.IdV, idAt);
Interlocked.Increment(ref _arpEntryUpdated);
}
}