///////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2010-2011 Artyom Beilis (Tonkikh) <artyomtnk@yahoo.com>
//
// Distributed under:
//
// the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// or (at your opinion) under:
//
// The MIT License
// (See accompanying file MIT.txt or a copy at
// http://www.opensource.org/licenses/mit-license.php)
//
///////////////////////////////////////////////////////////////////////////////
#define CPPDB_SOURCE
#include <cppdb/pool.h>
#include <cppdb/backend.h>
#include <cppdb/utils.h>
#include <cppdb/driver_manager.h>
#include <stdlib.h>
namespace cppdb {
struct pool::data {};
ref_ptr<pool> pool::create(connection_info const &ci)
{
ref_ptr<pool> p = new pool(ci);
return p;
}
ref_ptr<pool> pool::create(std::string const &cs)
{
connection_info ci(cs);
ref_ptr<pool> p = new pool(ci);
return p;
}
pool::pool(connection_info const &ci) :
limit_(0),
life_time_(0),
ci_(ci),
size_(0)
{
limit_ = ci_.get("@pool_size",16);
life_time_ = ci_.get("@pool_max_idle",600);
}
pool::~pool()
{
}
ref_ptr<backend::connection> pool::open()
{
if(limit_ == 0)
return driver_manager::instance().connect(ci_);
ref_ptr<backend::connection> p = get();
if(!p) {
p=driver_manager::instance().connect(ci_);
}
p->set_pool(this);
return p;
}
// this is thread safe member function
ref_ptr<backend::connection> pool::get()
{
if(limit_ == 0)
return 0;
ref_ptr<backend::connection> c;
pool_type garbage;
std::time_t now = time(0);
{
mutex::guard l(lock_);
// Nothing there should throw so it is safe
pool_type::iterator p = pool_.begin(),tmp;
while(p!=pool_.end()) {
if(p->last_used + life_time_ < now) {
tmp=p;
p++;
garbage.splice(garbage.begin(),pool_,tmp);
size_ --;
}
else {
// all is sorted by time
break;
}
}
if(!pool_.empty()) {
c = pool_.back().conn;
pool_.pop_back();
size_ --;
}
}
return c;
}
// this is thread safe member function
void pool::put(backend::connection *c_in)
{
std::auto_ptr<backend::connection> c(c_in);
if(limit_ == 0)
return;
pool_type garbage;
std::time_t now = time(0);
{
mutex::guard l(lock_);
// under lock do all very fast
if(c.get()) {
pool_.push_back(entry());
pool_.back().last_used = now;
pool_.back().conn = c.release();
size_ ++;
}
// Nothing there should throw so it is safe
pool_type::iterator p = pool_.begin(),tmp;
while(p!=pool_.end()) {
if(p->last_used + life_time_ < now) {
tmp=p;
p++;
garbage.splice(garbage.begin(),pool_,tmp);
size_ --;
}
else {
// all is sorted by time
break;
}
}
// can be at most 1 entry bigger then limit
if(size_ > limit_) {
garbage.splice(garbage.begin(),pool_,pool_.begin());
size_--;
}
}
}
void pool::gc()
{
put(0);
}
void pool::clear()
{
pool_type garbage;
{
mutex::guard l(lock_);
garbage.swap(pool_);
size_ = 0;
} // destroy outside mutex scope
}
}