Skip to content

Commit

Permalink
Packet factory is no longer recursive
Browse files Browse the repository at this point in the history
This is a breaking change, and comes with a bump to the version number.  The bottom line is that AutoFilters are no longer recursive with respect to contexts.  This change was necessary because, unlike events, AutoFilters operating under recursion can violate the confinement principle by attaching decorations.  This could cause a situation where two subcontexts interfere indirectly with each other due to attached decorations.

Rather than trying to provide a backwards-compatible path for this feature, the feature has instead been completely deprecated.  This feature's theory of operation will require closer examination and justification at a later time.
  • Loading branch information
codemercenary committed Dec 26, 2014
1 parent d6671e5 commit 6d7484e
Show file tree
Hide file tree
Showing 5 changed files with 3 additions and 126 deletions.
3 changes: 0 additions & 3 deletions autowiring/AutoPacketFactory.h
Expand Up @@ -33,9 +33,6 @@ class AutoPacketFactory:
~AutoPacketFactory(void);

private:
// Parent packet factory, if one exists:
Autowired<AutoPacketFactory> m_parent;

// Lock for this type
mutable std::mutex m_lock;

Expand Down
1 change: 0 additions & 1 deletion src/autowiring/AutoPacketFactory.cpp
Expand Up @@ -8,7 +8,6 @@

AutoPacketFactory::AutoPacketFactory(void):
ContextMember("AutoPacketFactory"),
m_parent(GetContext()->GetParentContext()),
m_packetCount(0),
m_packetDurationSum(0),
m_packetDurationSqSum(0)
Expand Down
9 changes: 2 additions & 7 deletions src/autowiring/AutoPacketInternal.cpp
Expand Up @@ -16,13 +16,8 @@ void AutoPacketInternal::Initialize(void) {
this->m_initTime = std::chrono::high_resolution_clock::now();

// Traverse all descendant contexts, adding their packet subscriber vectors one at a time:
for(const auto& curContext : ContextEnumerator(m_parentFactory->GetContext())) {
AutowiredFast<AutoPacketFactory> curFactory(curContext);
if(curFactory)
// Only insert if this context actually has a packet factory
curFactory->AppendAutoFiltersTo(m_satCounters);
}

m_parentFactory->AppendAutoFiltersTo(m_satCounters);

// Sort, eliminate duplicates
m_satCounters.sort();
m_satCounters.erase(std::unique(m_satCounters.begin(), m_satCounters.end()), m_satCounters.end());
Expand Down
114 changes: 0 additions & 114 deletions src/autowiring/test/AutoFilterTest.cpp
Expand Up @@ -32,58 +32,6 @@ TEST_F(AutoFilterTest, GetOutstandingTest) {
ASSERT_EQ(0UL, factory->GetOutstandingPacketCount()) << "Factory outstanding did not go to zero after releasing the only outstanding packet";
}

TEST_F(AutoFilterTest, VerifyDescendentAwareness) {
// Create a packet while the factory has no subscribers:
AutoRequired<AutoPacketFactory> parentFactory;
std::shared_ptr<AutoPacket> firstPacket = parentFactory->NewPacket();

// Verify subscription-free status:
EXPECT_FALSE(firstPacket->HasSubscribers<Decoration<0>>()) << "Subscription exists where one should not have existed";

std::shared_ptr<AutoPacket> strongPacket;
std::weak_ptr<AutoPacket> weakPacket;
std::weak_ptr<FilterA> filterChecker;

// Create a subcontext
{
AutoCreateContext subContext;
{
CurrentContextPusher pusher(subContext);

//add a filter in the subcontext
AutoRequired<FilterA> subFilter;
filterChecker = subFilter;
}
EXPECT_FALSE(firstPacket->HasSubscribers<Decoration<0>>()) << "Subscription was incorrectly, retroactively added to a packet";

//Create a packet where a subscriber exists only in a subcontext
strongPacket = parentFactory->NewPacket();
std::shared_ptr<AutoPacket> holdPacket = parentFactory->NewPacket();
weakPacket = holdPacket;
EXPECT_TRUE(strongPacket->HasSubscribers<Decoration<0>>()) << "Packet lacked expected subscription from subcontext";
EXPECT_TRUE(weakPacket.lock()->HasSubscribers<Decoration<0>>()) << "Packet lacked expected subscription from subcontext";
}
EXPECT_FALSE(filterChecker.expired()) << "Packet keeping subcontext member alive";

// Verify the second packet will no longer have subscriptions -
// normally removing a subscriber would mean the packet still has the subscriber, but
// in this case, the subscriber was actually destroyed so the packet has lost a subscriber.
EXPECT_TRUE(strongPacket->HasSubscribers<Decoration<0>>()) << "Missing subscriber from destroyed subcontext";

// Call the subscriber... this will either succeed or segfault.
strongPacket->Decorate(Decoration<0>());
strongPacket->Decorate(Decoration<1>());
EXPECT_TRUE(strongPacket->HasSubscribers<Decoration<0>>()) << "Calling a subscriber should not remove it";
{
std::shared_ptr<FilterA> holdFilter = filterChecker.lock();
ASSERT_EQ(1, holdFilter->m_called) << "Subcontext filter was not called";
}

// Create a packet after the subcontext has been destroyed
auto lastPacket = parentFactory->NewPacket();
EXPECT_FALSE(lastPacket->HasSubscribers<Decoration<0>>()) << "Subscription was incorrectly, retroactively added to a packet";
}

TEST_F(AutoFilterTest, VerifySimpleFilter) {
AutoRequired<AutoPacketFactory> factory;
AutoRequired<FilterA> filterA;
Expand Down Expand Up @@ -522,68 +470,6 @@ class DeferredAutoFilter:
size_t nReceived;
};

TEST_F(AutoFilterTest, DeferredRecieptInSubContext) {
static const size_t nPackets = 5;
AutoRequired<AutoPacketFactory> factory;
AutoRequired<DeferredAutoFilter>();

std::vector<std::weak_ptr<AutoPacket>> allPackets;

// Issue a packet before the subcontext is created, hold it for awhile:
auto preissued = factory->NewPacket();
preissued->Decorate(Decoration<0>());
allPackets.push_back(preissued);

{
// Create subcontext
AutoCreateContext ctxt;
CurrentContextPusher pshr(ctxt);
AutoRequired<DeferredAutoFilter> daf;

// Now we initiate:
ctxt->Initiate();

// Issue a few packets, have them get picked up by the subcontext:
for(size_t i = nPackets; i--;)
{
auto packet = factory->NewPacket();
packet->Decorate(Decoration<0>());
allPackets.push_back(packet);
}

// Terminate the subcontext, release references
ctxt->SignalShutdown(true);
ctxt->Wait();

// Verify that the filter got all of the packets that it should have gotten:
ASSERT_EQ(nPackets, daf->nReceived) << "AutoFilter did not get all packets that were pended to it";
}

// Release the preissued packet:
preissued.reset();

// Index of packets that were not expired at the time of detection
std::set<size_t> notExpired;

// Now verify that all of our packets are expired:
for(size_t i = 0; i < allPackets.size(); i++)
if(!allPackets[i].expired())
notExpired.insert(i);

if(!notExpired.empty()) {
// Delay for a bit, see if they expire later:
std::this_thread::sleep_for(std::chrono::seconds(1));
for(size_t i = 0; i < allPackets.size(); i++)
ASSERT_TRUE(allPackets[i].expired()) << "Packet " << i << " did not expire even after a delay that should have allowed it to expire";

// They did, tell the user what didn't expire the first time around
std::stringstream ss;
for(auto index : notExpired)
ss << index << " ";
FAIL() << "These packets did not expire after all recipients went out of scope: " << ss.str();
}
}

class HasAWeirdAutoFilterMethod {
public:
HasAWeirdAutoFilterMethod(void):
Expand Down
2 changes: 1 addition & 1 deletion version.cmake
@@ -1 +1 @@
set(autowiring_VERSION 0.3.2)
set(autowiring_VERSION 0.4.0)

0 comments on commit 6d7484e

Please sign in to comment.