diff options
author | Bernard Normier <bernard@zeroc.com> | 2007-06-27 16:27:24 -0400 |
---|---|---|
committer | Bernard Normier <bernard@zeroc.com> | 2007-06-27 16:27:24 -0400 |
commit | 85a70987f18610fb4d4eac2eded8155a9b2a6031 (patch) | |
tree | bba146de64978f6804149bfe524c53f6b5c0bc97 /cpp/src/Freeze/TransactionalEvictorI.cpp | |
parent | minor edits (diff) | |
download | ice-85a70987f18610fb4d4eac2eded8155a9b2a6031.tar.bz2 ice-85a70987f18610fb4d4eac2eded8155a9b2a6031.tar.xz ice-85a70987f18610fb4d4eac2eded8155a9b2a6031.zip |
Freeze transaction attributes + new Freeze/casino demo
Diffstat (limited to 'cpp/src/Freeze/TransactionalEvictorI.cpp')
-rw-r--r-- | cpp/src/Freeze/TransactionalEvictorI.cpp | 358 |
1 files changed, 195 insertions, 163 deletions
diff --git a/cpp/src/Freeze/TransactionalEvictorI.cpp b/cpp/src/Freeze/TransactionalEvictorI.cpp index 273eb4c6216..f9629432ec6 100644 --- a/cpp/src/Freeze/TransactionalEvictorI.cpp +++ b/cpp/src/Freeze/TransactionalEvictorI.cpp @@ -20,6 +20,19 @@ using namespace std; using namespace Freeze; using namespace Ice; +namespace +{ + +// +// Must be in sync with Parser.cpp +// + +const int supports = 0; +const int mandatory = 1; +const int required = 2; +const int never = 3; +} + // // createEvictor functions @@ -76,7 +89,7 @@ Freeze::TransactionalEvictorI::TransactionalEvictorI(const ObjectAdapterPtr& ada { } - virtual Ice::DispatchStatus dispatch(Ice::Request& request) + virtual DispatchStatus dispatch(Request& request) { return _evictor->dispatch(request); } @@ -119,7 +132,7 @@ Freeze::TransactionalEvictorI::setCurrentTransaction(const TransactionPtr& tx) } -Ice::ObjectPrx +ObjectPrx Freeze::TransactionalEvictorI::addFacet(const ObjectPtr& servant, const Identity& ident, const string& facet) { checkIdentity(ident); @@ -146,7 +159,7 @@ Freeze::TransactionalEvictorI::addFacet(const ObjectPtr& servant, const Identity if(!store->insert(ident, rec, tx)) { - Ice::AlreadyRegisteredException ex(__FILE__, __LINE__); + AlreadyRegisteredException ex(__FILE__, __LINE__); ex.kindOfObject = "servant"; ex.id = _communicator->identityToString(ident); if(!facet.empty()) @@ -164,7 +177,7 @@ Freeze::TransactionalEvictorI::addFacet(const ObjectPtr& servant, const Identity return obj; } -Ice::ObjectPtr +ObjectPtr Freeze::TransactionalEvictorI::removeFacet(const Identity& ident, const string& facet) { checkIdentity(ident); @@ -318,14 +331,15 @@ Freeze::TransactionalEvictorI::finished(const Current&, const ObjectPtr&, const // } -Ice::DispatchStatus -Freeze::TransactionalEvictorI::dispatch(Ice::Request& request) +DispatchStatus +Freeze::TransactionalEvictorI::dispatch(Request& request) { class CtxHolder { public: - CtxHolder(const TransactionalEvictorContextPtr& ctx, const SharedDbEnvPtr& dbEnv) : + CtxHolder(bool ownCtx, const TransactionalEvictorContextPtr& ctx, const SharedDbEnvPtr& dbEnv) : + _ownCtx(ownCtx), _ctx(ctx), _dbEnv(dbEnv) { @@ -333,20 +347,24 @@ Freeze::TransactionalEvictorI::dispatch(Ice::Request& request) ~CtxHolder() { - try - { - _ctx->commit(); - } - catch(...) + if(_ownCtx) { + try + { + _ctx->commit(); + } + catch(...) + { + _dbEnv->setCurrentTransaction(0); + throw; + } _dbEnv->setCurrentTransaction(0); - throw; } - _dbEnv->setCurrentTransaction(0); } private: - TransactionalEvictorContextPtr _ctx; + const bool _ownCtx; + const TransactionalEvictorContextPtr _ctx; const SharedDbEnvPtr& _dbEnv; }; @@ -360,205 +378,219 @@ Freeze::TransactionalEvictorI::dispatch(Ice::Request& request) { servantNotFound(__FILE__, __LINE__, current); } - - // - // Is there an existing context? - // + TransactionalEvictorContextPtr ctx = _dbEnv->getCurrent(); - - if(ctx != 0) + + ObjectPtr sample = store->sampleServant(); + ObjectPtr cachedServant = 0; + + TransactionalEvictorContext::ServantHolder servantHolder; + + if(sample == 0) { - try + if(ctx != 0) + { + try + { + servantHolder.init(ctx, current, store); + } + catch(const DeadlockException&) + { + ctx->deadlockException(); + throw; + } + sample = servantHolder.servant(); + } + else { // - // If yes, use this context; there is no retrying + // find / load read-only servant // - TransactionalEvictorContext::ServantHolder servantHolder(ctx, current, store, _useNonmutating); - - if(servantHolder.servant() == 0) + + cachedServant = loadCachedServant(current.id, store); + + if(cachedServant == 0) { servantNotFound(__FILE__, __LINE__, current); } - - try - { - DispatchStatus dispatchStatus = servantHolder.servant()->ice_dispatch(request, ctx); + sample = cachedServant; + } + } + + assert(sample != 0); + + int operationAttributes = sample->ice_operationAttributes(current.operation); - if(dispatchStatus == DispatchUserException && _rollbackOnUserException) - { - ctx->rollback(); - } + bool readOnly = (_useNonmutating && current.mode == Nonmutating) + || (!_useNonmutating && (operationAttributes & 0x1) == 0); + + int txMode = (operationAttributes & 0x6) >> 1; + + bool ownCtx = false; - if(dispatchStatus == DispatchAsync) - { - // - // May throw DeadlockException - // - ctx->checkDeadlockException(); - } - return dispatchStatus; + // + // Establish the proper context + // + switch(txMode) + { + case never: + { + assert(readOnly); + if(ctx != 0) + { + throw DatabaseException(__FILE__, __LINE__, "transaction rejected by 'never' metadata"); } - catch(...) + break; + } + case supports: + { + assert(readOnly); + break; + } + case mandatory: + { + if(ctx == 0) { - // - // Important: this rollback() ensures that servant holder destructor won't perform - // any database operation, and hence will not throw. - // - ctx->rollback(); - throw; + throw DatabaseException(__FILE__, __LINE__, "operation with a mandatory transaction"); } - // - // servantHolder destructor runs here and may throw (if tx was not rolled back) - // + break; } - catch(const DeadlockException&) + case required: { - ctx->deadlockException(); - throw; + if(ctx == 0) + { + ownCtx = true; + } + break; } - catch(...) + default: { - ctx->rollback(); - throw; + assert(0); } } - else + + if(ctx == 0 && !ownCtx) { - ObjectPtr servant = 0; - // - // Otherwise, first figure out if it's a read or write operation + // Read-only dispatch // - bool readOnly = true; - - if(_useNonmutating) - { - readOnly = (current.mode == Ice::Nonmutating); - } - else + assert(readOnly); + if(cachedServant == 0) { - // - // Is there a sample-servant associated with this store? - // + cachedServant = loadCachedServant(current.id, store); - ObjectPtr sample = store->sampleServant(); - if(sample != 0) + if(cachedServant == 0) { - readOnly = (sample->ice_operationAttributes(current.operation) & 0x1) == 0; - } - else - { - // - // Otherwise find / load read-only servant - // - servant = loadCachedServant(current.id, store); - if(servant == 0) - { - servantNotFound(__FILE__, __LINE__, current); - } - else - { - readOnly = (servant->ice_operationAttributes(current.operation) & 0x1) == 0; - } + servantNotFound(__FILE__, __LINE__, current); } } - + return cachedServant->ice_dispatch(request); + } + else + { // - // readOnly is now set properly + // Create a new transaction; retry on DeadlockException // - if(readOnly) + + bool tryAgain = false; + + do { - if(servant == 0) + try { - servant = loadCachedServant(current.id, store); - if(servant == 0) + if(ownCtx) { - servantNotFound(__FILE__, __LINE__, current); + ctx = _dbEnv->createCurrent(); } - } - // otherwise reuse servant loaded above - - // - // Non-transactional, read-only dispatch - // - return servant->ice_dispatch(request); - } - else - { - // - // Create a new transaction; retry on DeadlockException - // - - bool tryAgain = false; - - do - { + + CtxHolder ctxHolder(ownCtx, ctx, _dbEnv); + try - { - ctx = _dbEnv->createCurrent(); - CtxHolder ctxHolder(ctx, _dbEnv); - - try - { - TransactionalEvictorContext::ServantHolder servantHolder(ctx, current, store, _useNonmutating); - - if(servantHolder.servant() == 0) - { - servantNotFound(__FILE__, __LINE__, current); - } + { + TransactionalEvictorContext::ServantHolder sh; + if(servantHolder.initialized()) + { + // + // Adopt it + // + sh.adopt(servantHolder); + } + else + { + sh.init(ctx, current, store); + } + + if(sh.servant() == 0) + { + servantNotFound(__FILE__, __LINE__, current); + } + + if(!readOnly) + { + sh.markReadWrite(); + } - try + try + { + DispatchStatus dispatchStatus = sh.servant()->ice_dispatch(request, ctx); + if(dispatchStatus == DispatchUserException && _rollbackOnUserException) { - DispatchStatus dispatchStatus = servantHolder.servant()->ice_dispatch(request, ctx); - if(dispatchStatus == DispatchUserException && _rollbackOnUserException) - { - ctx->rollback(); - } - if(dispatchStatus == DispatchAsync) - { - // - // May throw DeadlockException - // - ctx->checkDeadlockException(); - } - - return dispatchStatus; + ctx->rollback(); } - catch(...) + if(dispatchStatus == DispatchAsync) { // - // Important: this rollback() ensures that servant holder destructor won't perform - // any database operation, and hence will not throw. + // May throw DeadlockException // - ctx->rollback(); - throw; + ctx->checkDeadlockException(); } - // - // servant holder destructor runs here and may throw (if !rolled back) - // - } - catch(const DeadlockException&) - { - ctx->deadlockException(); - throw; + + return dispatchStatus; } catch(...) { + // + // Important: this rollback() ensures that servant holder destructor won't perform + // any database operation, and hence will not throw. + // ctx->rollback(); throw; } - - // - // commit occurs here! // + // servant holder destructor runs here and may throw (if !rolled back) + // } catch(const DeadlockException&) { - tryAgain = true; + ctx->deadlockException(); + throw; + } + catch(...) + { + if(ownCtx) + { + ctx->rollback(); + } + throw; } - } while(tryAgain); - } + // + // commit occurs here (when ownCtx) + // + } + catch(const DeadlockException&) + { + if(ownCtx) + { + tryAgain = true; + } + else + { + throw; + } + } + + } while(tryAgain); } // @@ -633,7 +665,7 @@ Freeze::TransactionalEvictorI::evict() } -Ice::ObjectPtr +ObjectPtr Freeze::TransactionalEvictorI::loadCachedServant(const Identity& ident, ObjectStore<TransactionalEvictorElement>* store) { for(;;) @@ -664,7 +696,7 @@ Freeze::TransactionalEvictorI::loadCachedServant(const Identity& ident, ObjectSt } } -Ice::ObjectPtr +ObjectPtr Freeze::TransactionalEvictorI::evict(const Identity& ident, ObjectStore<TransactionalEvictorElement>* store) { // |