C++ (17+) için thread-safe, yüksek performanslı PostgreSQL Connection Pooling kütüphanesi
Github Repository: https://github.com/leventkaragol/libcpp-pg-pool
Amaç
Yüksek trafikli ve multi-threaded uygulamaların temel zorluklarından biri, veritabanı kaynaklarını verimli ve güvenli bir şekilde yönetmektir. Her bir veritabanı operasyonu için yeniden bağlantı kurmak, hem ciddi bir latency maliyeti yaratır, hem de sunucu üzerinde bir performans darboğazına neden olur. libcpp-pg-pool, bu kritik soruna yönelik, PostgreSQL için özel olarak tasarlanmış, hem thread-safe hem de yüksek performanslı bir connection pool kütüphanesidir. Kütüphanenin temel amacı, maliyetli bağlantı oluşturma işlemlerini en aza indirerek, hazırda bekleyen bir bağlantı havuzunu birden çok thread arasında güvenli bir şekilde paylaştırmaktır.
Projeye Nasıl Eklenir?
Bu header-only bir kütüphanedir. Yani aslında tek yapmanız gereken src klasöründeki libcpp-pg-pool.hpp dosyasını projenize eklemek ve #include ile kullanmaya başlamaktır.
Ancak bu kütüphane, arka planda libpqxx kütüphanesini kullanır. Dolayısıyla, kullanmadan önce projenize libpqxx kütüphanesini eklemeniz gerekir.
Kullanım örneklerini Github Repository'deki "examples" klasöründe bulabilirsiniz. Aşağıda örnek bir CMakeLists.txt dosyası içeriği de bulabilirsiniz.
cmake_minimum_required(VERSION 3.14)
project(myProject)
find_package(libpqxx CONFIG REQUIRED)
add_executable(myProject main.cpp libcpp-pg-pool.hpp)
target_link_libraries(myProject PRIVATE libpqxx::pqxx)
Nasıl Kullanılır? (En Basit Haliyle)
Yeni bir bağlantı elde etmek için "acquire" metodunu kullanabilirsiniz. "acquire" metodundan döndürülen değer bir Shared Pointer'dır ve bağlantı kapsam dışına çıktığı anda otomatik olarak havuza geri döndürülür. Bu nedenle, bağlantıyı manuel olarak kapatmanıza gerek yoktur.
Dikkat!
Bağlantı Havuzu uygulamada yalnızca bir kez oluşturulmalıdır. Havuz boyutuna bağlı olarak hazır olması 1 saniyeye kadar sürebilir.
#include "libcpp-pg-pool.hpp"
using namespace lklibs;
int main() {
const auto connectionString = "dbname=my_db user=my_user password=my_password host=localhost port=5432";
// Bağlantı havuzu boyutunu isteğe bağlı olarak belirtebilirsiniz, ancak belirtmezseniz varsayılan değer 100 olacaktır
PgPool pool(connectionString, 10);
{
// Havuzdan bir bağlantı alın
const auto dbConnection = pool.acquire();
pqxx::work txn(*dbConnection);
const auto result = txn.exec("SELECT * FROM my_table");
for (const auto& row : result)
{
std::cout << row[0].c_str() << std::endl;
}
}
// dbConnection kapsam dışına çıktığında bağlantı otomatik olarak havuza geri döndürülür
// Bu sayede bağlantıyı manuel olarak kapatmanıza gerek kalmaz
return 0;
}
Dikkat!
Bağlantı havuzu boyutu PostgreSQL'in max_connections sınırını aşmamalıdır, aksi takdirde "too many clients" gibi bir hata alırsınızPaylaşımlı Bağlantılar
"acquire" metodundan dönen değer, bir Shared Pointer'dır ve paylaşılan referansları sayar. Bir bağlantı açıp başka bir sınıfla paylaştığınızda, eldeki bağlantı nesnesi kapsam dışına çıksa bile, son paylaşılan sınıf nesnesi yok edilene kadar bağlantı açık kalır.
#include "libcpp-pg-pool.hpp"
using namespace lklibs;
class SampleConsumer
{
public:
void setDbConnection(std::shared_ptr<pqxx::connection> dbConnection)
{
this->dbConnection = std::move(dbConnection);
}
void queryData() const
{
pqxx::work txn(*dbConnection);
const auto result = txn.exec("SELECT * FROM my_table");
for (const auto& row : result)
{
std::cout << row[0].c_str() << std::endl;
}
}
[[nodiscard]] bool isConnectionOpen() const
{
return dbConnection->is_open();
}
private:
std::shared_ptr<pqxx::connection> dbConnection;
};
int main() {
const auto connectionString = "dbname=my_db user=my_user password=my_password host=localhost port=5432";
PgPool pool(connectionString);
{
SampleConsumer myConsumer{};
{
// Havuzdan bir bağlantı alın
const auto dbConnection = pool.acquire();
// Bağlantı SampleConsumer ile paylaşıldı
myConsumer.setDbConnection(dbConnection);
myConsumer.queryData();
}
// dbConnection kapsam dışına çıktıktan sonra bile bağlantı hala canlı kalır çünkü SampleConsumer hala shared_ptr'yi tutuyor
std::cout << "Connection status:" << myConsumer.isConnectionOpen() << std::endl;
}
// Bağlantıyı tutan tüm shared_ptr'ler kapsam dışına çıktığında bağlantı otomatik olarak havuza geri döndürülür
return 0;
Semantik Versiyonlama
Kütüphanenin sürümlemesi, geleneksel semantik versiyonlama kullanılarak yapılır. Buna göre, MAJOR.MINOR.PATCH biçiminde yapılan sürümlemede;
PATCH: Olası hata düzeltmeleri ve iyileştirmeleri içerir. Bunu mutlaka edinmek istersiniz.
MINOR: Geriye dönük uyumluluk sayesinde eklenen ek işlevler. Muhtemelen bunu edinmek istersiniz, zararı olmaz.
MAJOR: Geriye dönük uyumluluğu bozan ek işlevler. Nelerin değiştiğini anlamanız ve muhtemelen kendi kodunuzda değişiklik yapmanız gerekecek. Böyle bir şey yayınlarsam, geçiş için gereken değişiklikleri kesinlikle dokümana eklerim.
Lisans
Proje MIT lisansı ile lisanslanmıştır. Ticari kullanıma uygundur. Tam metni aşağıda bulabilirsiniz.
MIT License
Copyright (c) 2024 Levent KARAGÖL
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
without restriction, including without limitation the rights to use, copy, modify,
merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies
or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
İletişim
Kütüphaneyle ilgili sorun yaşıyorsanız, lütfen GitHub'da bir konu açın. Lütfen isteğinizi, sorununuzu veya sorunuzu olabildiğince ayrıntılı bir şekilde açıklayın ve derleyicinizin, işletim sisteminizin ve kullandığınız kütüphanenin sürümünü de belirtin. Yeni bir konu açmadan önce, lütfen konunun daha önce kapatılmış konularda bulunmadığından emin olun.
Yazar: Levent KARAGÖL