Project

General

Profile

Bug #2535 » WtSessionDisconnect.patch

Saif Rehman, 05/23/2014 10:47 PM

View differences:

src/Wt/Dbo/Session
*/
void rereadAll(const char *tableName = 0);
/*! \brief Disconnects all objects from session management.
*
* This disconnects all objects from the session management.
* Disconnected objects are not synchronized with the database.
*/
virtual void disconnectAll();
/*! \brief Discards all unflushed changes.
*
* This method is useful when the flushMode() is set to Manual. It discards
......
virtual void dropTable(Session& session,
std::set<std::string>& tablesDropped);
virtual void rereadAll();
virtual void disconnectAll();
std::string primaryKeys() const;
};
......
virtual void dropTable(Session& session,
std::set<std::string>& tablesDropped);
virtual void rereadAll();
virtual void disconnectAll();
};
typedef const std::type_info * const_typeinfo_ptr;
src/Wt/Dbo/Session.C
throw Exception("Not to be done.");
}
void Session::MappingInfo::disconnectAll()
{
throw Exception("Not to be done.");
}
std::string Session::MappingInfo::primaryKeys() const
{
if (surrogateIdFieldName)
......
i->second->rereadAll();
}
void Session::disconnectAll()
{
if (!dirtyObjects_.empty())
std::cerr << "Warning: Wt::Dbo::Session disconnecting with "
<< dirtyObjects_.size() << " dirty objects" << std::endl;
for (MetaDboBaseSet::iterator i = dirtyObjects_.begin();
i != dirtyObjects_.end(); ++i)
(*i)->decRef();
dirtyObjects_.clear();
for (ClassRegistry::iterator i = classRegistry_.begin();
i != classRegistry_.end(); ++i)
i->second->disconnectAll();
}
void Session::discardUnflushed()
{
objectsToAdd_.clear();
src/Wt/Dbo/Session_impl.h
}
template <class C>
void Session::Mapping<C>::disconnectAll()
{
for (typename Registry::iterator i = registry_.begin();
i != registry_.end(); ++i) {
i->second->setSession(0);
i->second->setState(MetaDboBase::Disconnected);
}
registry_.clear();
}
template <class C>
void Session::Mapping<C>::init(Session& session)
{
if (!initialized_) {
src/Wt/Dbo/ptr
New = 0x000,
Persisted = 0x001,
Orphaned = 0x002,
Disconnected = 0x004,
// flags
NeedsDelete = 0x010,
......
bool isPersisted() const
{ return 0 != (state_ & (Persisted | SavedInTransaction)); }
bool isOrphaned() const { return 0 != (state_ & Orphaned); }
bool isDisconnected() const { return 0 != (state_ & Disconnected); }
bool isDeleted() const
{ return 0 != (state_ & (NeedsDelete | DeletedInTransaction)); }
......
int refCount_;
void checkNotOrphaned();
void checkNotDisconnected();
};
/*! \class dbo_default_traits Wt/Dbo/Dbo Wt/Dbo/Dbo
src/Wt/Dbo/ptr.C
}
}
void MetaDboBase::checkNotDisconnected()
{
if (isDisconnected()) {
throw Exception("modifying disconnected dbo ptr");
}
}
ptr_base::~ptr_base()
{ }
src/Wt/Dbo/ptr_impl.h
if (refCount_)
throw std::logic_error("Dbo: refCount > 0");
if ((!isOrphaned()) && session())
if ((!isOrphaned()) && (!isDisconnected()) && session())
session()->prune(this);
delete obj_;
......
void MetaDbo<C>::flush()
{
checkNotOrphaned();
checkNotDisconnected();
if (state_ & NeedsDelete) {
state_ &= ~NeedsDelete;
test/dbo/DboDisconnectTest.C
/*
* Copyright (C) 2009 Emweb bvba, Kessel-Lo, Belgium.
*
* See the LICENSE file for terms of use.
*/
#include <boost/test/unit_test.hpp>
#include <Wt/Dbo/Dbo>
#include <Wt/Dbo/backend/Postgres>
#include <Wt/Dbo/backend/MySQL>
#include <Wt/Dbo/backend/Sqlite3>
#include <Wt/Dbo/backend/Firebird>
#include <Wt/WDate>
#include <Wt/WDateTime>
#include <Wt/WTime>
#include <Wt/Dbo/WtSqlTraits>
#include <Wt/Dbo/ptr_tuple>
#include <string>
namespace dbo = Wt::Dbo;
class TestDbo;
typedef dbo::collection< dbo::ptr<TestDbo> > TestDboCollection;
class TestDbo : public Wt::Dbo::Dbo<TestDbo>
{
public:
int intC;
double doubleC;
template<class Action>
void persist(Action &a)
{
Wt::Dbo::field(a, intC, "intC");
Wt::Dbo::field(a, doubleC, "doubleC");
}
static const char *TableName()
{
return "func";
}
};
struct Dbo3Fixture
{
typedef std::map<long long, Wt::Dbo::ptr<TestDbo>> TestMapType;
TestMapType TestMap;
dbo::SqlConnection *connection_;
dbo::Session *session_;
Dbo3Fixture()
{
connection_ = new dbo::backend::Sqlite3(":memory:");
connection_->setProperty("show-queries", "true");
session_ = new dbo::Session();
session_->setConnection(*connection_);
session_->mapClass<TestDbo>(TestDbo::TableName());
session_->createTables();
{
dbo::Transaction tr(*session_);
dbo::ptr<TestDbo> New1 = session_->add(new TestDbo());
New1.modify()->intC = 1;
New1.modify()->doubleC = 1.1;
dbo::ptr<TestDbo> New2 = session_->add(new TestDbo());
New2.modify()->intC = 2;
New2.modify()->doubleC = 2.2;
}
{
//Check initial values
FetchAll();
dbo::ptr<TestDbo> DisconnectedTestPtr = TestMap[1]; //id: 1
std::cout << "Before modified: intC: " << DisconnectedTestPtr->intC << ", expected: 1" << std::endl;
//Modify from outside session_'s knowledge
dbo::Transaction tr(*session_);
session_->execute(std::string("UPDATE ") + TestDbo::TableName() + " SET intC = 99 WHERE id = 1;");
tr.commit();
//Check again
FetchAll();
//should remain unchanged because in FetchAll() none of the ptr<C>s are deleted or modified but swapped with a local TestMap object
std::cout << "After re-fetched: intC: " << DisconnectedTestPtr->intC << ", expected: 1" << std::endl;
//should be a new value because FetchAll uses a collection to map all ptr<C> with newer values from the database
dbo::ptr<TestDbo> NormalTestPtr = TestMap[1]; //id: 1
std::cout << "After re-assignment: intC: " << NormalTestPtr->intC << ", expected: 99" << std::endl;
BOOST_REQUIRE(DisconnectedTestPtr->intC == 1);
BOOST_REQUIRE(NormalTestPtr->intC == 99);
dbo::Transaction tr2(*session_);
NormalTestPtr.modify()->intC = 10;
tr2.commit();
try
{
dbo::Transaction tr3(*session_);
DisconnectedTestPtr.modify()->intC = 5;
tr3.commit();
}
catch(std::exception &e)
{
std::cout << "Exception caught: " << e.what();
}
}
}
void FetchAll()
{
//Strong exception safety(make TestMap empty by swapping with an empty map, swap back if exception is caught)
TestMapType testmap;
TestMap.swap(testmap);
session_->disconnectAll();
try
{
dbo::Transaction tr(*session_);
TestDboCollection collection = session_->find<TestDbo>();
for(TestDboCollection::const_iterator itr = collection.begin();
itr != collection.end();
++itr)
{
TestMap[itr->id()] = *itr;
}
tr.commit();
}
catch(...)
{
testmap.swap(TestMap);
}
}
~Dbo3Fixture()
{
session_->dropTables();
delete session_;
delete connection_;
}
};
BOOST_AUTO_TEST_CASE( dbo3_reload_test )
{
Dbo3Fixture f;
}
(2-2/2)