D2: definitive conclusion — revision-write requires non-WCF storage-engine pipe
IL walk of the native wrapper:
HistorianAccess.AddRevisionValuesBegin (private, token 0x06006175)
-> CClientCommon.AddNonStreamValuesBegin
-> CClient.AddNonStreamValuesBegin (8-instr overload)
-> CClient.TransactionBegin
-> CHistStorageConnection.StartTransaction (token 0x06001FDD)
-> CStorageEngineConsoleClient.StartTransaction
CStorageEngineConsoleClient is built on STransactPipeClient2 +
SCrtMemFile — a shared-memory + named-pipe transport to
aaStorageEngine.exe, completely separate from WCF.
The WCF ITransactionServiceContract2.AddNonStreamValuesBegin2 op is a
server-side relay that requires a pre-existing storage-engine pipe
session for the client. Without that pipe session, the WCF relay returns
UnknownClient (51) — and there's no way to establish the pipe session
via WCF.
D2 is unimplementable as a pure-managed-WCF SDK. The native wrapper
itself depends on the C++ shared-memory channel; replicating that from
managed code would require implementing the storage-engine pipe
protocol, which is a major undertaking and out of scope.
The ITransactionServiceContract2 declaration in our contracts file
stays as documentation; no public API or orchestrator added.
HistorianWcfRevisionOrchestrator remains as an internal probe /
regression check — re-run the probe test if anyone believes the
architecture has changed.
178/178 tests still pass.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -175,16 +175,48 @@ A future session that wants to push further should try (in order):
|
||||
chain — confirmed `RTag2` itself succeeds (returns 25-byte response),
|
||||
but `AddNonStreamValuesBegin2` still fails with `UnknownClient`.
|
||||
So RTag2 doesn't cascade client identity to Trx.
|
||||
2. Try `IStorageServiceContract` ops (`AddT`, `AddTP`) on `/Storage`
|
||||
— that endpoint isn't currently bound by our SDK but the contract
|
||||
is declared in `Wcf/Contracts/IStorageServiceContract.cs`. Maybe
|
||||
one of its ops registers the client with Trx as a side effect.
|
||||
3. Decompile / IL-walk `aahClientCommon.CClientCommon` methods that
|
||||
the native code calls between Open2 and AddNonStreamValuesBegin
|
||||
to find any "client-with-Trx" registration we're missing.
|
||||
4. As a last resort, decompile `aahClientAccessPoint.exe` (the server
|
||||
binary) to find what populates Trx's session table — the answer
|
||||
is in there, just not in the client surface.
|
||||
2. ⚠️ **OBVIATED 2026-05-05** by finding (3): `IStorageServiceContract`
|
||||
ops aren't the missing piece either, because the missing piece isn't
|
||||
on the WCF surface at all.
|
||||
3. ✅ **DONE 2026-05-05** — IL walk of `aahClientCommon.CClientCommon.AddNonStreamValuesBegin`
|
||||
↓ `aahClientCommon.CClient.AddNonStreamValuesBegin`
|
||||
↓ `aahClientCommon.CClient.TransactionBegin`
|
||||
reveals the chain ultimately invokes
|
||||
**`aahClientCommon.CHistStorageConnection.StartTransaction`** (token
|
||||
`0x06001FDD`) which calls **`CStorageEngineConsoleClient.StartTransaction`**.
|
||||
`CStorageEngineConsoleClient` is built on `STransactPipeClient2` +
|
||||
`SCrtMemFile` — a **shared-memory + named-pipe** transport to the
|
||||
storage engine, completely separate from WCF.
|
||||
|
||||
### Definitive architectural conclusion (2026-05-05)
|
||||
|
||||
The revision-write path uses **two transports in tandem**:
|
||||
|
||||
1. WCF (`/Hist`, `/Retr`, `/Stat`, `/Trx`) — what our SDK speaks
|
||||
2. **Shared-memory + named-pipe to `aaStorageEngine.exe`** — what
|
||||
`CStorageEngineConsoleClient` speaks; the SDK doesn't (and would be
|
||||
a major project to implement)
|
||||
|
||||
The WCF `ITransactionServiceContract2.AddNonStreamValuesBegin2` op we
|
||||
were probing is a server-side relay that requires a pre-existing
|
||||
storage-engine pipe session for the client. That session is established
|
||||
via the pipe channel, not WCF. Without the pipe-side session, the WCF
|
||||
relay returns `UnknownClient (51)` — and there's no way to establish
|
||||
the pipe-side session via WCF.
|
||||
|
||||
**D2 is unimplementable as a pure-managed-WCF SDK.** The native wrapper
|
||||
itself depends on the C++ shared-memory channel; to replicate that
|
||||
behavior from a managed client would require implementing the whole
|
||||
storage-engine pipe protocol, which is out of scope and probably
|
||||
not viable without deeper RE of `aaStorageEngine.exe` itself.
|
||||
|
||||
The WCF `ITransactionServiceContract2` declaration in our contracts
|
||||
file is left in place — it's correct as a contract — but no
|
||||
orchestrator or public surface should be added on top of it. The
|
||||
`HistorianWcfRevisionOrchestrator` in `src/AVEVA.Historian.Client/Wcf/`
|
||||
remains as an internal probe / regression check; if anyone ever
|
||||
believes the architecture has changed, re-run the probe test to
|
||||
verify the gate still holds.
|
||||
|
||||
### Current state of the SDK-direct probe
|
||||
|
||||
|
||||
Reference in New Issue
Block a user