Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 13 additions & 4 deletions cpp-lib/include/SnaccROSEInterfaces.h
Original file line number Diff line number Diff line change
Expand Up @@ -154,17 +154,18 @@ class SnaccInvokeContext
{
public:
static std::shared_ptr<SnaccInvokeContext> Create(const SnaccInvokeContextInit& init);

/*! Builds the invoke-context snapshot stored on @ref SnaccTelemetryData.
Calls @ref Clone(), clears lib-owned async decode borrows on the clone, then @ref PrepareForTelemetry(). */
virtual std::shared_ptr<SnaccInvokeContext> CloneForTelemetryRetention() const final;

virtual std::shared_ptr<SnaccInvokeContext> Clone() const;

SnaccInvokeContext& operator=(const SnaccInvokeContext&) = delete;
SnaccInvokeContext(SnaccInvokeContext&&) = delete;
SnaccInvokeContext& operator=(SnaccInvokeContext&&) = delete;
virtual ~SnaccInvokeContext();

// Called immediately before the context is transferred into telemetry retention.
// Override if derived types keep borrowed data that must be detached or copied.
virtual void PrepareForTelemetry();

// Meaning in OnInvoke_: Authentication Header from the ROSE Invoke (Pointer to the object in the invoke)
// Meaning in Invoke_: Authentication Header that is dispatched along with the invoke (create it with new, cleanup is done inside)
// SNACC::ROSEAuthRequest* pInvokeAuth{};
Expand Down Expand Up @@ -220,6 +221,14 @@ class SnaccInvokeContext
// Allows derived context types to copy the base invoke-context state into a richer concrete type.
SnaccInvokeContext(const SnaccInvokeContext& other);

/*! Called on a telemetry-retained clone after @ref CloneForTelemetryRetention() copied dispatch state.
Dispatch often stores non-owning raw pointers (stub @c ROSEInvoke, transport, session objects)
that are only valid while snacclib is still inside the invoke scope. Before the clone is
stored on @ref SnaccTelemetryData, override this to copy any needed fields into owned members,
then clear those pointers so telemetry cannot outlive the stub stack frame. The live dispatch
context is not modified. Lib-owned async result/error buffers are already cleared before this hook. */
virtual void PrepareForTelemetry();

std::string m_strOperationName;
int m_iInvokeTimeout{-1};
SnaccInvokeAsyncCallback m_asyncCallback;
Expand Down
18 changes: 14 additions & 4 deletions cpp-lib/src/SnaccROSEBase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,20 @@ std::shared_ptr<SnaccInvokeContext> SnaccInvokeContext::Clone() const
return std::shared_ptr<SnaccInvokeContext>(new SnaccInvokeContext(*this));
}

std::shared_ptr<SnaccInvokeContext> SnaccInvokeContext::CloneForTelemetryRetention() const
{
auto retained = Clone();
retained->m_asyncCallback = {};
retained->m_pAsyncResult = nullptr;
retained->m_pAsyncError = nullptr;
retained->PrepareForTelemetry();
return retained;
}

void SnaccInvokeContext::PrepareForTelemetry()
{
}

SnaccScopedInvokeMessage::SnaccScopedInvokeMessage(long invokeID, unsigned int uiOperationID, SNACC::AsnType* pArgument)
: m_pInvoke(new SNACC::ROSEInvoke())
{
Expand Down Expand Up @@ -323,10 +337,6 @@ SnaccInvokeContext::~SnaccInvokeContext()
}
}

void SnaccInvokeContext::PrepareForTelemetry()
{
}

void SnaccInvokeContext::SetInvokeTimeout(int iTimeoutMs)
{
m_iInvokeTimeout = iTimeoutMs;
Expand Down
5 changes: 1 addition & 4 deletions cpp-lib/src/SnaccTelemetry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,10 +130,7 @@ void SnaccTelemetryData::finalize(Outcome outcome, Stage stage, Reason reason, s

std::shared_ptr<SnaccInvokeContext> pTelemetryctx;
if (pctx)
{
pTelemetryctx = pctx->Clone();
pTelemetryctx->PrepareForTelemetry();
}
pTelemetryctx = pctx->CloneForTelemetryRetention();

m_Duration = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - m_ChronoCreated);
m_Outcome = outcome;
Expand Down
14 changes: 13 additions & 1 deletion cpp-lib/tests/telemetry_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,13 @@ const SnaccTelemetryData* FindOutboundWaitTelemetry(const std::vector<std::share
return FindTelemetry(entries, SnaccTelemetryData::Direction::OUTBOUND, SnaccTelemetryData::Stage::OUTBOUND_WAIT, reason);
}

void ExpectTelemetryInvokeContextLibBorrowsCleared(const SnaccInvokeContext& ctx)
{
EXPECT_FALSE(ctx.HasAsyncCompletion());
EXPECT_EQ(nullptr, ctx.AsyncResultBuffer());
EXPECT_EQ(nullptr, ctx.AsyncErrorBuffer());
}

void ExpectOutboundWaitTelemetry(const SnaccTelemetryData* pTelemetry, const SnaccTelemetryData::Outcome outcome, const SnaccTelemetryData::Reason reason, const std::optional<long> roseResult,
const bool bExpectRequestData, const bool bExpectResponseData)
{
Expand All @@ -52,6 +59,8 @@ void ExpectOutboundWaitTelemetry(const SnaccTelemetryData* pTelemetry, const Sna
EXPECT_GT(pTelemetry->m_stResponseData.value(), 0u);
}
EXPECT_GE(pTelemetry->m_Duration.count(), 0);
if (pTelemetry->m_pctx)
ExpectTelemetryInvokeContextLibBorrowsCleared(*pTelemetry->m_pctx);
}

long SendAsyncGetSettings(RuntimeEndpoint& client, AsyncInvokeLatch& latch, AsnGetSettingsResult& result, AsnRequestError& error, int timeoutMs)
Expand Down Expand Up @@ -265,7 +274,7 @@ class TelemetryRuntimeTest : public RuntimeTestBase
}

// Verifies that outbound telemetry receives a cloned custom context and that
// PrepareForTelemetry only touches the retained clone.
// retention cleanup only touches the retained clone.
void AssertCustomContextIsClonedAndPrepared(const TransportEncoding encoding)
{
InitializeEndpoints(encoding);
Expand Down Expand Up @@ -293,6 +302,9 @@ class TelemetryRuntimeTest : public RuntimeTestBase
EXPECT_EQ("client-session", pSessionCtx->m_strInvokeSessionId);
EXPECT_TRUE(pSessionCtx->WasPreparedForTelemetry());
EXPECT_EQ("prepared:custom", pSessionCtx->TelemetryNote());
ExpectTelemetryInvokeContextLibBorrowsCleared(*pSessionCtx);
EXPECT_EQ(nullptr, pSessionCtx->DispatchBorrowForTest());
EXPECT_NE(nullptr, dynamic_cast<SessionInvokeContext*>(pCtx.get())->DispatchBorrowForTest());
}

// Verifies that outbound transport failures are reported at OUTBOUND_SEND.
Expand Down
18 changes: 14 additions & 4 deletions cpp-lib/tests/test_support/sample_runtime_harness.h
Original file line number Diff line number Diff line change
Expand Up @@ -260,9 +260,10 @@ class SessionInvokeContext : public SnaccInvokeContext
return std::shared_ptr<SnaccInvokeContext>(new SessionInvokeContext(*this));
}

// Placeholder hook for future telemetry tests that may need to detach data.
// Records that PrepareForTelemetry() ran on the telemetry-retained clone.
void PrepareForTelemetry() override
{
m_pDispatchBorrow = nullptr;
m_bPreparedForTelemetry = true;
if (!m_strTelemetryNote.empty())
m_strTelemetryNote = "prepared:" + m_strTelemetryNote;
Expand All @@ -280,12 +281,18 @@ class SessionInvokeContext : public SnaccInvokeContext
return m_strTelemetryNote;
}

// Returns whether PrepareForTelemetry() has already run on this concrete instance.
// Returns whether retention cleanup has already run on this concrete instance.
bool WasPreparedForTelemetry() const
{
return m_bPreparedForTelemetry;
}

// Simulates a product-owned dispatch borrow; cleared in PrepareForTelemetry() on the telemetry clone.
const SNACC::ROSEInvoke* DispatchBorrowForTest() const
{
return m_pDispatchBorrow;
}

const std::string m_strLocalSessionId; // session id of the endpoint creating the context
const std::string m_strInvokeSessionId; // session id carried on the invoke payload itself

Expand All @@ -294,7 +301,8 @@ class SessionInvokeContext : public SnaccInvokeContext
SessionInvokeContext(const SnaccInvokeContextInit& init, const std::string& localSessionId)
: SnaccInvokeContext(init),
m_strLocalSessionId(localSessionId),
m_strInvokeSessionId(GetInvokeSessionId(init.m_pInvoke))
m_strInvokeSessionId(GetInvokeSessionId(init.m_pInvoke)),
m_pDispatchBorrow(init.m_pInvoke)
{
}

Expand All @@ -304,12 +312,14 @@ class SessionInvokeContext : public SnaccInvokeContext
m_strLocalSessionId(other.m_strLocalSessionId),
m_strInvokeSessionId(other.m_strInvokeSessionId),
m_bPreparedForTelemetry(other.m_bPreparedForTelemetry),
m_strTelemetryNote(other.m_strTelemetryNote)
m_strTelemetryNote(other.m_strTelemetryNote),
m_pDispatchBorrow(other.m_pDispatchBorrow)
{
}

bool m_bPreparedForTelemetry = false; // indicates whether the telemetry clone was normalized for retention
std::string m_strTelemetryNote; // extra test data used to verify clone and prepare semantics
const SNACC::ROSEInvoke* m_pDispatchBorrow = nullptr;
};

// Copies invoke-context fields while the runtime reference is still alive.
Expand Down
6 changes: 3 additions & 3 deletions version.h
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
#ifndef VERSION_H
#define VERSION_H

#define VERSION "7.0.9"
#define VERSION_RC 7, 0, 9
#define RELDATE "16.07.2026"
#define VERSION "7.0.10"
#define VERSION_RC 7, 0, 10
#define RELDATE "24.07.2026"

#endif // VERSION_H
Loading