summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Goodliffe <dan@randomdan.homeip.net>2015-11-18 01:25:50 +0000
committerDan Goodliffe <dan@randomdan.homeip.net>2015-11-18 01:25:50 +0000
commit89231894c7cd095b811129ca034e31b9017610fb (patch)
tree8138cd14c79a3a1b43c6bd7a4c29fc0b6f1cc5cd
parentPrevent test failed due to race condition (diff)
downloadlibadhocutil-89231894c7cd095b811129ca034e31b9017610fb.tar.bz2
libadhocutil-89231894c7cd095b811129ca034e31b9017610fb.tar.xz
libadhocutil-89231894c7cd095b811129ca034e31b9017610fb.zip
Implement and test resource testing and replacement on reuse.
-rw-r--r--libadhocutil/resourcePool.h2
-rw-r--r--libadhocutil/resourcePool.impl.h32
-rw-r--r--libadhocutil/unittests/testResourcePool.cpp37
3 files changed, 56 insertions, 15 deletions
diff --git a/libadhocutil/resourcePool.h b/libadhocutil/resourcePool.h
index f3683ae..5ccb516 100644
--- a/libadhocutil/resourcePool.h
+++ b/libadhocutil/resourcePool.h
@@ -76,7 +76,7 @@ namespace AdHoc {
/// Create a new resource instance to add to the pool.
virtual Resource * createResource() const = 0;
/// Destroy an existing resource (defaults to delete).
- virtual void destroyResource(Resource *) const;
+ virtual void destroyResource(Resource *) const throw();
/// Test a cached resource is still suitable for use (defaults to no-op).
virtual void testResource(const Resource *) const;
diff --git a/libadhocutil/resourcePool.impl.h b/libadhocutil/resourcePool.impl.h
index d4fcfe4..85a6d3d 100644
--- a/libadhocutil/resourcePool.impl.h
+++ b/libadhocutil/resourcePool.impl.h
@@ -98,7 +98,7 @@ namespace AdHoc {
template <typename R>
void
- ResourcePool<R>::destroyResource(R * r) const
+ ResourcePool<R>::destroyResource(R * r) const throw()
{
delete r;
}
@@ -166,20 +166,24 @@ namespace AdHoc {
ResourceHandle<R>
ResourcePool<R>::getOne()
{
- UpgradableLock(lock, ulock);
- if (available.empty()) {
- auto ro = new typename ResourceHandle<R>::Object(createResource(), this);
- UpgradeLock(ulock);
- inUse.insert({ std::this_thread::get_id(), ro });
- return ro;
- }
- else {
- UpgradeLock(ulock);
- auto ro = new typename ResourceHandle<R>::Object(available.front(), this);
- available.pop_front();
- inUse.insert({ std::this_thread::get_id(), ro });
- return ro;
+ Lock(lock);
+ while (!available.empty()) {
+ auto r = available.front();
+ try {
+ testResource(r);
+ auto ro = new typename ResourceHandle<R>::Object(r, this);
+ available.pop_front();
+ inUse.insert({ std::this_thread::get_id(), ro });
+ return ro;
+ }
+ catch (...) {
+ destroyResource(r);
+ available.pop_front();
+ }
}
+ auto ro = new typename ResourceHandle<R>::Object(createResource(), this);
+ inUse.insert({ std::this_thread::get_id(), ro });
+ return ro;
}
template <typename R>
diff --git a/libadhocutil/unittests/testResourcePool.cpp b/libadhocutil/unittests/testResourcePool.cpp
index 6e62730..349ea00 100644
--- a/libadhocutil/unittests/testResourcePool.cpp
+++ b/libadhocutil/unittests/testResourcePool.cpp
@@ -245,3 +245,40 @@ BOOST_AUTO_TEST_CASE( threading2 )
BOOST_REQUIRE_EQUAL(1, pool.availableCount());
}
+class TTRP : public TRP {
+ public:
+ TTRP() : n(0) { }
+ void testResource(const MockResource *) const override
+ {
+ n += 1;
+ if (n % 2) {
+ throw std::exception();
+ }
+ }
+ private:
+ mutable int n;
+};
+
+BOOST_AUTO_TEST_CASE( test )
+{
+ TTRP pool;
+ MockResource * rp;
+ {
+ auto r = pool.get();
+ rp = r.get();
+ }
+ {
+ auto r = pool.get();
+ BOOST_REQUIRE(r.get());
+ BOOST_REQUIRE(rp != r.get());
+ BOOST_REQUIRE_EQUAL(1, MockResource::count);
+ rp = r.get();
+ }
+ {
+ auto r = pool.get();
+ BOOST_REQUIRE(r.get());
+ BOOST_REQUIRE(rp == r.get());
+ BOOST_REQUIRE_EQUAL(1, MockResource::count);
+ }
+}
+