diff options
-rw-r--r-- | cpp/src/Freeze/TransactionalEvictorContext.cpp | 14 | ||||
-rw-r--r-- | cpp/src/Freeze/TransactionalEvictorContext.h | 8 | ||||
-rw-r--r-- | cpp/src/Freeze/TransactionalEvictorI.cpp | 5 | ||||
-rw-r--r-- | cpp/test/Freeze/evictor/Client.cpp | 41 | ||||
-rw-r--r-- | cpp/test/Freeze/evictor/Test.ice | 8 | ||||
-rw-r--r-- | cpp/test/Freeze/evictor/TestI.cpp | 119 | ||||
-rw-r--r-- | cpp/test/Freeze/evictor/TestI.h | 4 | ||||
-rw-r--r-- | java/test/Freeze/evictor/AccountI.java | 10 |
8 files changed, 194 insertions, 15 deletions
diff --git a/cpp/src/Freeze/TransactionalEvictorContext.cpp b/cpp/src/Freeze/TransactionalEvictorContext.cpp index 395203ed805..ac9466d017e 100644 --- a/cpp/src/Freeze/TransactionalEvictorContext.cpp +++ b/cpp/src/Freeze/TransactionalEvictorContext.cpp @@ -119,11 +119,23 @@ Freeze::TransactionalEvictorContext::checkDeadlockException() } } +bool +Freeze::TransactionalEvictorContext::clearUserException() +{ + bool result = _userExceptionDetected; + _userExceptionDetected = false; + return result; +} + bool -Freeze::TransactionalEvictorContext::response(bool) +Freeze::TransactionalEvictorContext::response(bool ok) { if(_owner == IceUtil::ThreadControl()) { + if(!ok) + { + _userExceptionDetected = true; + } return true; } else diff --git a/cpp/src/Freeze/TransactionalEvictorContext.h b/cpp/src/Freeze/TransactionalEvictorContext.h index f9bcb1aa375..12b2a2e8765 100644 --- a/cpp/src/Freeze/TransactionalEvictorContext.h +++ b/cpp/src/Freeze/TransactionalEvictorContext.h @@ -112,6 +112,8 @@ public: void checkDeadlockException(); + bool clearUserException(); + void commit(); void rollback(); @@ -145,12 +147,16 @@ private: bool _rollbackOnly; std::auto_ptr<DeadlockException> _deadlockException; - + // // Protected by this // bool _deadlockExceptionDetected; + // + // Not protected (used only by dispatch thread) + // + bool _userExceptionDetected; }; typedef IceUtil::Handle<TransactionalEvictorContext> TransactionalEvictorContextPtr; diff --git a/cpp/src/Freeze/TransactionalEvictorI.cpp b/cpp/src/Freeze/TransactionalEvictorI.cpp index f9629432ec6..eb359c22368 100644 --- a/cpp/src/Freeze/TransactionalEvictorI.cpp +++ b/cpp/src/Freeze/TransactionalEvictorI.cpp @@ -543,6 +543,11 @@ Freeze::TransactionalEvictorI::dispatch(Request& request) // May throw DeadlockException // ctx->checkDeadlockException(); + + if(ctx->clearUserException() && _rollbackOnUserException) + { + ctx->rollback(); + } } return dispatchStatus; diff --git a/cpp/test/Freeze/evictor/Client.cpp b/cpp/test/Freeze/evictor/Client.cpp index 0d090a33e80..a11d4cc23a3 100644 --- a/cpp/test/Freeze/evictor/Client.cpp +++ b/cpp/test/Freeze/evictor/Client.cpp @@ -371,6 +371,8 @@ public: void run() { + int transferOp = 0; + for(int i = 0; i < 1000; i++) { // @@ -385,9 +387,36 @@ public: } while(from == to); + try { - from->transfer(100, to); + // + // Alternate between transfer methods + // + switch(transferOp) + { + case 0: + { + from->transfer(100, to); + break; + } + case 1: + { + from->transfer2(100, to); + break; + } + case 2: + { + from->transfer3(100, to); + break; + } + default: + { + test(false); + } + }; + transferOp++; + transferOp = transferOp % 3; } catch(const Test::InsufficientFundsException&) { @@ -403,12 +432,12 @@ public: // test(false); } - + /* - if(i % 100 == 0) - { - cerr << "." << flush; - } + if(i % 100 == 0) + { + cerr << "." << flush; + } */ } } diff --git a/cpp/test/Freeze/evictor/Test.ice b/cpp/test/Freeze/evictor/Test.ice index adfc5827bf7..4770603c8da 100644 --- a/cpp/test/Freeze/evictor/Test.ice +++ b/cpp/test/Freeze/evictor/Test.ice @@ -38,6 +38,14 @@ class Account ["freeze:write"] void transfer(int amount, Account* toAccount) throws InsufficientFundsException; // + // Other implementations of transfer that we want to test as well + // + ["freeze:write", "amd"] void transfer2(int amount, Account* toAccount) throws InsufficientFundsException; + ["freeze:write", "amd"] void transfer3(int amount, Account* toAccount) throws InsufficientFundsException; + + + + // // "Internal" operation // ["freeze:write:mandatory"] void deposit(int amount) throws InsufficientFundsException; diff --git a/cpp/test/Freeze/evictor/TestI.cpp b/cpp/test/Freeze/evictor/TestI.cpp index ba64434c0aa..df6c87176ac 100644 --- a/cpp/test/Freeze/evictor/TestI.cpp +++ b/cpp/test/Freeze/evictor/TestI.cpp @@ -45,6 +45,125 @@ Test::AccountI::transfer(int amount, const Test::AccountPrx& toAccount, const Cu deposit(-amount, current); // direct call } +void +Test::AccountI::transfer2_async(const AMD_Account_transfer2Ptr& cb, int amount, const Test::AccountPrx& toAccount, const Current& current) +{ + // + // Here the dispatch thread does everything + // + test(_evictor->getCurrentTransaction() != 0); + + try + { + toAccount->deposit(amount); // collocated call + deposit(-amount, current); // direct call + } + catch(const InsufficientFundsException& ex) + { + cb->ice_exception(ex); + return; + } + + cb->ice_response(); +} + + +class ResponseThread : public IceUtil::Thread, private IceUtil::Monitor<IceUtil::Mutex> +{ +public: + + ResponseThread(const Test::AMD_Account_transfer3Ptr& cb) : + _cb(cb), + _response(false) + { + } + + void response() + { + Lock sync(*this); + _response = true; + notify(); + } + + void exception(const Ice::UserException& e) + { + Lock sync(*this); + _exception.reset(dynamic_cast<Ice::UserException*>(e.ice_clone())); + notify(); + } + + + virtual void run() + { + Lock sync(*this); + + bool timedOut = false; + + while(!timedOut && _response == false && _exception.get() == 0) + { + timedOut = !timedWait(IceUtil::Time::seconds(1)); + } + + if(timedOut) + { + return; + } + + if(_response) + { + _cb->ice_response(); + } + else if(_exception.get() != 0) + { + _cb->ice_exception(*_exception.get()); + } + else + { + _cb->ice_exception(Ice::TimeoutException(__FILE__, __LINE__)); + } + } + +private: + Test::AMD_Account_transfer3Ptr _cb; + bool _response; + std::auto_ptr<Ice::UserException> _exception; +}; +typedef IceUtil::Handle<ResponseThread> ResponseThreadPtr; + + +void +Test::AccountI::transfer3_async(const AMD_Account_transfer3Ptr& cb, int amount, const Test::AccountPrx& toAccount, const Current& current) +{ + // + // Here the dispatch thread does the actual work, but a separate thread sends the response + // + + ResponseThreadPtr thread = new ResponseThread(cb); + thread->start(33000).detach(); + + test(_evictor->getCurrentTransaction() != 0); + + try + { + toAccount->deposit(amount); // collocated call + deposit(-amount, current); // direct call + } + catch(const Ice::UserException& e) + { + // + // Need to rollback here -- "rollback on user exception" does not work + // when the dispatch commits before it gets any response! + // + _evictor->getCurrentTransaction()->rollback(); + + thread->exception(e); + return; + } + + thread->response(); +} + + Test::AccountI::AccountI(int initialBalance, const Freeze::TransactionalEvictorPtr& evictor) : Account(initialBalance), _evictor(evictor) diff --git a/cpp/test/Freeze/evictor/TestI.h b/cpp/test/Freeze/evictor/TestI.h index 9f39463a190..adcf6664ad0 100644 --- a/cpp/test/Freeze/evictor/TestI.h +++ b/cpp/test/Freeze/evictor/TestI.h @@ -33,6 +33,10 @@ public: virtual void transfer(int, const Test::AccountPrx&, const Ice::Current&); + virtual void transfer2_async(const AMD_Account_transfer2Ptr&, int, const Test::AccountPrx&, const Ice::Current&); + + virtual void transfer3_async(const AMD_Account_transfer3Ptr&, int, const Test::AccountPrx&, const Ice::Current&); + AccountI(int, const Freeze::TransactionalEvictorPtr&); AccountI(); diff --git a/java/test/Freeze/evictor/AccountI.java b/java/test/Freeze/evictor/AccountI.java index 081ea041ce9..6c61949eef9 100644 --- a/java/test/Freeze/evictor/AccountI.java +++ b/java/test/Freeze/evictor/AccountI.java @@ -54,6 +54,7 @@ public class AccountI extends Test.Account catch(Test.InsufficientFundsException ex) { cb.ice_exception(ex); + return; } cb.ice_response(); @@ -68,11 +69,6 @@ public class AccountI extends Test.Account class ResponseThread extends Thread { - ResponseThread(Test.AMD_Account_transfer3 cb) - { - _cb = cb; - } - synchronized void response() { _response = true; @@ -127,12 +123,11 @@ public class AccountI extends Test.Account } } - private Test.AMD_Account_transfer3 _cb; private boolean _response = false; private Ice.UserException _exception; }; - ResponseThread thread = new ResponseThread(cb); + ResponseThread thread = new ResponseThread(); thread.setDaemon(true); thread.start(); @@ -152,6 +147,7 @@ public class AccountI extends Test.Account _evictor.getCurrentTransaction().rollback(); thread.exception(e); + return; } thread.response(); |