int Test::ServantI::getTotalBalance(const Current& current) { Test::AccountPrxSeq proxies = getAccounts(current); // // Need to start a transaction to ensure a consistent result // Freeze::TransactionalEvictorPtr te = Freeze::TransactionalEvictorPtr::dynamicCast(_evictor); for(;;) { test(te->getCurrentTransaction() == 0); Freeze::ConnectionPtr con = Freeze::createConnection(current.adapter->getCommunicator(), _remoteEvictor->envName()); te->setCurrentTransaction(con->beginTransaction()); int total = 0; try { for(size_t i = 0; i < proxies.size(); ++i) { total += proxies[i]->getBalance(); } te->getCurrentTransaction()->rollback(); te->setCurrentTransaction(0); return total; } catch(const Freeze::TransactionalEvictorDeadlockException&) { te->getCurrentTransaction()->rollback(); te->setCurrentTransaction(0); // retry } catch(...) { te->getCurrentTransaction()->rollback(); te->setCurrentTransaction(0); throw; } } return -1; }
int run(int, char**, const Ice::CommunicatorPtr& communicator, bool transactional, bool shutdown) { string ref = "factory:default -p 12010"; Ice::ObjectPrx base = communicator->stringToProxy(ref); test(base); Test::RemoteEvictorFactoryPrx factory = Test::RemoteEvictorFactoryPrx::checkedCast(base); if(transactional) { cout << "testing transactional Freeze Evictor... " << flush; } else { cout << "testing background-save Freeze Evictor... " << flush; } const Ice::Int size = 5; Ice::Int i; Test::RemoteEvictorPrx evictor = factory->createEvictor("Test", transactional); evictor->setSize(size); // // Create some servants // vector<Test::ServantPrx> servants; for(i = 0; i < size; i++) { ostringstream ostr; ostr << i; string id = ostr.str(); servants.push_back(evictor->createServant(id, i)); servants[i]->ice_ping(); Test::FacetPrx facet1 = Test::FacetPrx::uncheckedCast(servants[i], "facet1"); try { facet1->ice_ping(); test(false); } catch(const Ice::FacetNotExistException&) { // Expected } servants[i]->addFacet("facet1", "data"); facet1->ice_ping(); facet1 = Test::FacetPrx::checkedCast(servants[i], "facet1"); test(facet1); facet1->setValue(10 * i); facet1->addFacet("facet2", "moreData"); Test::FacetPrx facet2 = Test::FacetPrx::checkedCast(facet1, "facet2"); test(facet2); facet2->setValue(100 * i); } // // Evict and verify values. // evictor->setSize(0); evictor->setSize(size); for(i = 0; i < size; i++) { test(servants[i]->getValue() == i); Test::FacetPrx facet1 = Test::FacetPrx::checkedCast(servants[i], "facet1"); test(facet1); test(facet1->getValue() == 10 * i); test(facet1->getData() == "data"); Test::FacetPrx facet2 = Test::FacetPrx::checkedCast(facet1, "facet2"); test(facet2); test(facet2->getData() == "moreData"); } // // Mutate servants. // for(i = 0; i < size; i++) { servants[i]->setValue(i + 100); Test::FacetPrx facet1 = Test::FacetPrx::checkedCast(servants[i], "facet1"); test(facet1); facet1->setValue(10 * i + 100); Test::FacetPrx facet2 = Test::FacetPrx::checkedCast(facet1, "facet2"); test(facet2); facet2->setValue(100 * i + 100); } // // Evict and verify values. // evictor->setSize(0); evictor->setSize(size); for(i = 0; i < size; i++) { test(servants[i]->getValue() == i + 100); Test::FacetPrx facet1 = Test::FacetPrx::checkedCast(servants[i], "facet1"); test(facet1); test(facet1->getValue() == 10 * i + 100); Test::FacetPrx facet2 = Test::FacetPrx::checkedCast(facet1, "facet2"); test(facet2); test(facet2->getValue() == 100 * i + 100); } if(!transactional) { // // Test saving while busy // for(i = 0; i < size; i++) { // // Start a mutating operation so that the object is not idle. // servants[i]->begin_setValueAsync(i + 300); test(servants[i]->getValue() == i + 100); // // This operation modifies the object state but is not saved // because the setValueAsync operation is still pending. // servants[i]->setValue(i + 200); test(servants[i]->getValue() == i + 200); // // Force the response to setValueAsync // servants[i]->releaseAsync(); test(servants[i]->getValue() == i + 300); } } // // Add duplicate facet and catch corresponding exception // for(i = 0; i < size; i++) { try { servants[i]->addFacet("facet1", "foobar"); test(false); } catch(const Test::AlreadyRegisteredException&) { } } // // Remove a facet that does not exist // try { servants[0]->removeFacet("facet3"); test(false); } catch(const Test::NotRegisteredException&) { } // // Call an operation that does not exist on the servant // try { Test::AccountPrx::uncheckedCast(servants[0])->getBalance(); test(false); } catch(const Ice::OperationNotExistException&) { } // // Remove all facets // for(i = 0; i < size; i++) { servants[i]->removeFacet("facet1"); servants[i]->removeFacet("facet2"); } // // Check they are all gone // for(i = 0; i < size; i++) { Test::FacetPrx facet1 = Test::FacetPrx::checkedCast(servants[i], "facet1"); test(facet1 == 0); Test::FacetPrx facet2 = Test::FacetPrx::checkedCast(servants[i], "facet2"); test(facet2 == 0); } evictor->setSize(0); evictor->setSize(size); // // Destroy servants and verify ObjectNotExistException. // for(i = 0; i < size; i++) { servants[i]->destroy(); try { servants[i]->getValue(); test(false); } catch(const Ice::ObjectNotExistException&) { // Expected } try { servants[i]->ice_ping(); test(false); } catch(const Ice::ObjectNotExistException&) { // Expected } } // // Recreate servants, set transient value // servants.clear(); for(i = 0; i < size; i++) { ostringstream ostr; ostr << i; string id = ostr.str(); servants.push_back(evictor->createServant(id, i)); servants[i]->setTransientValue(i); } // // Evict all // evictor->saveNow(); evictor->setSize(0); evictor->setSize(size); // // Check the transient value // for(i = 0; i < size; i++) { test(servants[i]->getTransientValue() == -1); } if(!transactional) { // // Now with keep // for(i = 0; i < size; i++) { servants[i]->keepInCache(); servants[i]->keepInCache(); servants[i]->setTransientValue(i); } evictor->saveNow(); evictor->setSize(0); evictor->setSize(size); // // Check the transient value // for(i = 0; i < size; i++) { test(servants[i]->getTransientValue() == i); } // // Again, after one release // for(i = 0; i < size; i++) { servants[i]->release(); } evictor->saveNow(); evictor->setSize(0); evictor->setSize(size); for(i = 0; i < size; i++) { test(servants[i]->getTransientValue() == i); } // // Again, after a second release // for(i = 0; i < size; i++) { servants[i]->release(); } evictor->saveNow(); evictor->setSize(0); evictor->setSize(size); for(i = 0; i < size; i++) { test(servants[i]->getTransientValue() == -1); } // // Release one more time // for(i = 0; i < size; i++) { try { servants[i]->release(); test(false); } catch(const Test::NotRegisteredException&) { // Expected } } } if(transactional) { int totalBalance = servants[0]->getTotalBalance(); test(totalBalance == 0); Test::AccountPrxSeq accounts = servants[0]->getAccounts(); test(accounts.size() > 0); totalBalance = servants[0]->getTotalBalance(); test(totalBalance > 0); const int threadCount = static_cast<int>(accounts.size()); vector<ThreadPtr> threads(threadCount); for(i = 0; i < threadCount; i++) { threads[i] = new TransferThread(accounts); threads[i]->start(); } for(i = 0; i < threadCount; i++) { threads[i]->getThreadControl().join(); } // // Check that the total balance did not change! // test(totalBalance == servants[0]->getTotalBalance()); } // // Deactivate and recreate evictor, to ensure that servants // are restored properly after database close and reopen. // evictor->deactivate(); evictor = factory->createEvictor("Test", transactional); evictor->setSize(size); for(i = 0; i < size; i++) { ostringstream ostr; ostr << i; string id = ostr.str(); servants[i] = evictor->getServant(id); test(servants[i]->getValue() == i); } // // Test concurrent lookups with a smaller evictor // size and one missing servant // evictor->setSize(size / 2); servants[0]->destroy(); { const int threadCount = size * 2; ThreadPtr threads[threadCount]; for(i = 0; i < threadCount; i++) { threads[i] = new ReadThread(servants); threads[i]->start(); } for(i = 0; i < threadCount; i++) { threads[i]->getThreadControl().join(); } } // // Clean up. // evictor->destroyAllServants(""); evictor->destroyAllServants("facet1"); evictor->destroyAllServants("facet2"); // // CreateDestroy threads // { const int threadCount = size;; ThreadPtr threads[threadCount]; for(i = 0; i < threadCount; i++) { threads[i] = new CreateDestroyThread(evictor, i, size); threads[i]->start(); } for(i = 0; i < threadCount; i++) { threads[i]->getThreadControl().join(); } // // Verify all destroyed // for(i = 0; i < size; i++) { try { servants[i]->getValue(); test(false); } catch(const Ice::ObjectNotExistException&) { // Expected } } } // // Recreate servants. // servants.clear(); for(i = 0; i < size; i++) { ostringstream ostr; ostr << i; string id = ostr.str(); servants.push_back(evictor->createServant(id, i)); } // // Deactivate in the middle of remote AMD operations // (really testing Ice here) // { const int threadCount = size; ReadForeverThreadPtr threads[threadCount]; for(i = 0; i < threadCount; i++) { threads[i] = new ReadForeverThread(servants); threads[i]->start(); } ThreadControl::sleep(Time::milliSeconds(500)); for(i = 0; i < threadCount; i++) { threads[i]->setState(ReadForeverThread::StateDeactivating); } evictor->deactivate(); for(i = 0; i < threadCount; i++) { threads[i]->setState(ReadForeverThread::StateDeactivated); } for(i = 0; i < threadCount; i++) { threads[i]->getThreadControl().join(); } } // // Resurrect // evictor = factory->createEvictor("Test", transactional); evictor->destroyAllServants(""); // // Deactivate in the middle of adds // { const int threadCount = size; AddForeverThreadPtr threads[threadCount]; for(i = 0; i < threadCount; i++) { threads[i] = new AddForeverThread(evictor, i); threads[i]->start(); } ThreadControl::sleep(Time::milliSeconds(500)); for(i = 0; i < threadCount; i++) { threads[i]->setState(AddForeverThread::StateDeactivating); } evictor->deactivate(); for(i = 0; i < threadCount; i++) { threads[i]->setState(AddForeverThread::StateDeactivated); } for(i = 0; i < threadCount; i++) { threads[i]->getThreadControl().join(); } } // // Clean up. // evictor = factory->createEvictor("Test", transactional); evictor->destroyAllServants(""); evictor->deactivate(); cout << "ok" << endl; if(shutdown) { factory->shutdown(); } return EXIT_SUCCESS; }