Browse Source

Added support of unmounting of applications

master
Artyom Beilis 8 years ago
parent
commit
19f84a00af
4 changed files with 84 additions and 8 deletions
  1. +14
    -0
      cppcms/applications_pool.h
  2. +19
    -0
      src/applications_pool.cpp
  3. +29
    -6
      tests/pool_test.cpp
  4. +22
    -2
      tests/pool_test.py

+ 14
- 0
cppcms/applications_pool.h View File

@@ -197,6 +197,20 @@ namespace cppcms {
void mount(booster::shared_ptr<application_specific_pool> gen,mount_point const &point,int application_options = 0);


///
/// Unmount an application_specific_pool from the general pool.
///
/// Notes:
///
/// - Exiting request would continue to be executed
/// - There is no guarantee when and in which thread application objects would be destroyed upon use of unmount
/// - applications in the pool using thread_specific policy would be destroyed only on thread exit (i.e. when threads of thread pool are destroyed)
///
/// This member function is thread safe.
///
void unmount(booster::weak_ptr<application_specific_pool> gen);


/// \cond INTERNAL

/// get is not in use any more


+ 19
- 0
src/applications_pool.cpp View File

@@ -420,6 +420,10 @@ void applications_pool::mount(booster::shared_ptr<application_specific_pool> gen
if(flags & app::prepopulated)
gen->prepopulate(*srv_);
booster::unique_lock<booster::recursive_mutex> lock(d->lock);
for(std::list<_data::attachment>::iterator it = d->apps.begin();it!=d->apps.end();++it) {
if(it->pool == gen)
throw cppcms_error("Attempt to mount application_specific_pool twice");
}
d->apps.push_back(_data::attachment(gen,point));
}

@@ -460,6 +464,21 @@ applications_pool::get_application_specific_pool(char const *host,char const *sc
return result;
}

void applications_pool::unmount(booster::weak_ptr<application_specific_pool> wgen)
{
booster::shared_ptr<application_specific_pool> gen = wgen.lock();
if(!gen) return;
booster::unique_lock<booster::recursive_mutex> lock(d->lock);

for(std::list<_data::attachment>::iterator it = d->apps.begin();it!=d->apps.end();++it) {
if(it->pool == gen) {
d->apps.erase(it);
return;
}
}
}

booster::intrusive_ptr<application> applications_pool::get( char const *,
char const *,
char const *,


+ 29
- 6
tests/pool_test.cpp View File

@@ -151,6 +151,8 @@ private:
int original_thread_id_;
};

std::map<std::string,booster::weak_ptr<cppcms::application_specific_pool> > weak_pools;

class tester : public cppcms::application {
public:
tester(cppcms::service &srv) : cppcms::application(srv) {}
@@ -158,6 +160,15 @@ public:
{
if(name=="/stats")
counter::instance(request().get("id"))->print(response().out());
else if(name=="/unmount") {
std::string id = request().get("id");
bool exists_before = weak_pools[id].lock();
service().applications_pool().unmount(weak_pools[id]);
bool exists_after = weak_pools[id].lock();
response().out()<<"unmount=" << id << "\n"
"before="<<exists_before <<"\n"
"after="<<exists_after;
}
else if(name=="/install") {
app_ = new unit_test(service(),counter::instance("/async/temporary"));
service().applications_pool().mount(app_,cppcms::mount_point("/async","/temporary",0));
@@ -174,6 +185,16 @@ private:
};


struct marker {
marker(std::string const &name) : name_(name) {}
booster::shared_ptr<cppcms::application_specific_pool> const &operator | (booster::shared_ptr<cppcms::application_specific_pool> const &in)
{
weak_pools[name_] = in;
return in;
}
std::string name_;
};

int main(int argc,char **argv)
{
try {
@@ -184,7 +205,7 @@ int main(int argc,char **argv)
set_thread_id(1);
srv.applications_pool().mount(
cppcms::create_pool<unit_test>(counter::instance("/sync")),
marker("/sync") | cppcms::create_pool<unit_test>(counter::instance("/sync")),
mount_point("/sync","",0),
cppcms::app::synchronous);
@@ -194,26 +215,26 @@ int main(int argc,char **argv)
cppcms::app::synchronous);

srv.applications_pool().mount(
cppcms::create_pool<unit_test>(counter::instance("/sync/prepopulated")),
marker("/sync/prepopulated") | cppcms::create_pool<unit_test>(counter::instance("/sync/prepopulated")),
mount_point("/sync","/prepopulated",0),
cppcms::app::synchronous | cppcms::app::prepopulated);
srv.applications_pool().mount(
cppcms::create_pool<unit_test>(counter::instance("/sync/tss")),
marker("/sync/tss") | cppcms::create_pool<unit_test>(counter::instance("/sync/tss")),
mount_point("/sync","/tss",0),
cppcms::app::synchronous | cppcms::app::thread_specific);

srv.applications_pool().mount(
cppcms::applications_factory<unit_test>(counter::instance("/sync/legacy")),
mount_point("/sync","/legacy",0));
mount_point("/sync","/legacy",0));
srv.applications_pool().mount(
cppcms::create_pool<unit_test>(counter::instance("/async")),
marker("/async") | cppcms::create_pool<unit_test>(counter::instance("/async")),
mount_point("/async","",0),
cppcms::app::asynchronous);

srv.applications_pool().mount(
cppcms::create_pool<unit_test>(counter::instance("/async/prepopulated")),
marker("/async/prepopulated") | cppcms::create_pool<unit_test>(counter::instance("/async/prepopulated")),
mount_point("/async","/prepopulated",0),
cppcms::app::asynchronous | cppcms::app::prepopulated);

@@ -228,6 +249,8 @@ int main(int argc,char **argv)

srv.after_fork(thread_submitter(srv));
srv.run();

weak_pools.clear();
}

std::cout << "Test all deleted" << std::endl;


+ 22
- 2
tests/pool_test.py View File

@@ -36,6 +36,7 @@ class Conn():
r2 = response.split('\r\n\r\n')
headers=r2[0]
body = r2[1]
first_header = headers.split('\r\n')[0]
if exp404:
test(headers.find('HTTP/1.0 404')==0)
return {'status' : 404 }
@@ -49,7 +50,7 @@ class Conn():
r[ss[0]]=int(ss[1])
else:
r[ss[0]]=ss[1]
print now(), "Got",r
print now(), "Got",first_header,r
return r

def pool_many(url,cb=None):
@@ -63,7 +64,8 @@ def pool_many(url,cb=None):
a[i]=None

def test_sync():
print '/sync'
n='/sync'
print n
st=Conn('/test/stats?id=/sync').get()
test(st["total"]==0)

@@ -88,6 +90,9 @@ def test_sync():
test(st["total"]==2)
test(st["current"]==2)

st=Conn('/test/unmount?id='+n).get()
Conn(n).get(exp404 = True)
test(Conn('/test/stats?id='+n).get()["current"]==0)


def test_sync_prep():
@@ -112,9 +117,13 @@ def test_sync_prep():
test(st["total"]==2)
test(st["current"]==2)

Conn('/test/unmount?id='+n).get()
Conn(n).get(exp404 = True)
test(Conn('/test/stats?id='+n).get()["current"]==0)


def test_sync_ts():
n='/sync/tss'
print '/sync/tss'
st=Conn('/test/stats?id=/sync/tss').get()
test(st["total"]==0)
@@ -143,6 +152,9 @@ def test_sync_ts():
test(st["total"]==2)
test(st["current"]==2)

st=Conn('/test/unmount?id='+n).get()
Conn(n).get(exp404 = True)
test(Conn('/test/stats?id='+n).get()["current"]==2)


def test_sync_legacy():
@@ -187,6 +199,10 @@ def test_async():
st=Conn('/test/stats?id=' + n).get()
test(st["total"]==1)
test(st["current"]==1)
st=Conn('/test/unmount?id='+n).get()
Conn(n).get(exp404 = True)
test(Conn('/test/stats?id='+n).get()["current"]==0)

def test_async_prep():
n='/async/prepopulated'
@@ -205,6 +221,10 @@ def test_async_prep():
test(st["total"]==1)
test(st["current"]==1)

st=Conn('/test/unmount?id='+n).get()
Conn(n).get(exp404 = True)
test(Conn('/test/stats?id='+n).get()["current"]==0)

def test_async_legacy():
n='/async/legacy'
print n


Loading…
Cancel
Save