diff options
author | Eelco Dolstra <eelco.dolstra@logicblox.com> | 2016-02-23 15:00:59 +0100 |
---|---|---|
committer | Eelco Dolstra <eelco.dolstra@logicblox.com> | 2016-02-23 15:00:59 +0100 |
commit | e292144d46e3fbb24ee9ee67f1682b268373921b (patch) | |
tree | 318c8baaca0739076dcbcbe0d530f5e8d97fc204 /src/libutil/pool.hh | |
parent | c0b7a8a0b576d5fcbcb25c412836dc885b7eb0fe (diff) |
RemoteStore: Make thread-safe
This allows a RemoteStore object to be used safely from multiple
threads concurrently. It will make multiple daemon connections if
necessary.
Note: pool.hh and sync.hh have been copied from the Hydra source tree.
Diffstat (limited to 'src/libutil/pool.hh')
-rw-r--r-- | src/libutil/pool.hh | 102 |
1 files changed, 102 insertions, 0 deletions
diff --git a/src/libutil/pool.hh b/src/libutil/pool.hh new file mode 100644 index 000000000..d63912e28 --- /dev/null +++ b/src/libutil/pool.hh @@ -0,0 +1,102 @@ +#pragma once + +#include <memory> +#include <list> +#include <functional> + +#include "sync.hh" +#include "ref.hh" + +namespace nix { + +/* This template class implements a simple pool manager of resources + of some type R, such as database connections. It is used as + follows: + + class Connection { ... }; + + Pool<Connection> pool; + + { + auto conn(pool.get()); + conn->exec("select ..."); + } + + Here, the Connection object referenced by ‘conn’ is automatically + returned to the pool when ‘conn’ goes out of scope. +*/ + +template <class R> +class Pool +{ +public: + + typedef std::function<ref<R>()> Factory; + +private: + + Factory factory; + + struct State + { + unsigned int count = 0; + std::list<ref<R>> idle; + }; + + Sync<State> state; + +public: + + Pool(const Factory & factory = []() { return make_ref<R>(); }) + : factory(factory) + { } + + class Handle + { + private: + Pool & pool; + ref<R> r; + + friend Pool; + + Handle(Pool & pool, std::shared_ptr<R> r) : pool(pool), r(r) { } + + public: + Handle(Handle && h) : pool(h.pool), r(h.r) { abort(); } + + Handle(const Handle & l) = delete; + + ~Handle() + { + auto state_(pool.state.lock()); + state_->idle.push_back(r); + } + + R * operator -> () { return &*r; } + R & operator * () { return *r; } + }; + + Handle get() + { + { + auto state_(state.lock()); + if (!state_->idle.empty()) { + auto p = state_->idle.back(); + state_->idle.pop_back(); + return Handle(*this, p); + } + state_->count++; + } + /* Note: we don't hold the lock while creating a new instance, + because creation might take a long time. */ + return Handle(*this, factory()); + } + + unsigned int count() + { + auto state_(state.lock()); + return state_->count; + } +}; + +} |