Ivyware Msgcore Component reference Mgr · Field · Data · Heap Melbourne, AU
Ivyware

Ivyware/Msgcore/Architecture

Component reference

The store, and what lives inside it

Msgcore is a structured message store, not a serialisation library. One manager owns one heap; every field, value, child, attribute and container inside it is addressed by offset. Seven type families carry the whole model, and two caller-side rules govern all of them.

P2PmsgMgr

The store manager is the object you hold. It owns the heap, the root field and the whole lifetime of everything inside — there are no free-standing nodes, and nothing in a store outlives its manager.

  • A store has a name and a root descriptor. Fields are added to that root, and to each other, forming an ordered tree.
  • Save writes the heap image to a temporary file and renames it over the target. A concurrent reader either sees the previous store or the new one, never a partial write.
  • Load opens the image read-only and shared, and validates the header before walking it — a store that declares more than the file holds is refused rather than followed.
  • Fields are reachable by path as well as by traversal, so a caller that knows the shape can address a leaf directly instead of walking to it.
  • Triggers fire on changes within the store, which is how a consumer keeps a derived view in step without polling the tree.

A node is a path, not a pointer. That statement is the shortest correct summary of this library. Everything downstream of it — that growth is safe, that save is a copy, that a store is one file — follows from the store never having handed out an address in the first place.

P3PmsgField

A field is the unit everything else is built from: a name, a typed value, an ordered set of children and a set of attributes.

  • Children are ordered, and the order is part of the store — reading a saved image back gives the same sequence it was written in.
  • Attributes are qualified with @ and live beside the children rather than among them, so a scan for named children is not polluted by metadata.
  • A field can be found by name within its parent, or by path from the root. Both resolve to an offset.
  • Fields nest without limit, and the structure is self-describing — a reader that has never seen the shape can still walk it, name by name.

P3PmsgData

The value side of a field. One field, one value, of whatever type the caller assigned.

  • Native integer and floating types, booleans, dates and times.
  • Wide strings and BSTRs, sized in UTF-16 code units on every platform — the width does not change because the host's wchar_t does.
  • Binary blobs, XML fragments and images, stored in the same heap as everything else and resized as they are filled.
  • The value is written in place. There is no separate buffer to allocate, hand over and free.

MsgVBHeap

The offset-addressed heap and its block allocator. This is the piece that makes the rest of the design possible, and the piece a caller never touches directly.

  • Every reference is a displacement from the base of the image. Nothing inside a store holds a machine address, so nothing inside a store has to be corrected when the image moves.
  • Growth reallocates the base and copies. All existing offsets remain valid by construction; there is no fix-up pass anywhere in the library, because there is nothing to fix up.
  • The allocator keeps a free list, so a store that churns fields does not grow monotonically.
  • The addressing width is declared in the image, and an image may not declare a wider arena than the width it also declares. That combination is rejected on load.
  • An endian sentinel travels with the image and doubles as its layout generation, so a store written by a different byte order or a different layout is recognised instead of silently misread.

The one rule this creates. A raw pointer obtained from the heap does not survive a mutation: growth reallocates the base, and every pointer previously handed out dangles. Re-resolve from the offset after any operation that can allocate. This is stated at the declarations that govern it in the shipped C header, not only here.

The containers

List, vector, stack and cursor types over a field's children — and the attribute and descriptor collections. They are laid out inside the heap rather than wrapped around it, which is why they persist with the store instead of having to be rebuilt after a load.

Container types
TypeUse
MsgListThe ordered child ring of a field. Insertion and removal at any position.
MsgVectIndexed access over a block of items, for children that are addressed by position rather than by name.
MsgStckA stack inside the store — used for value stacks and for nesting during traversal.
MsgCursA cursor over a ring. It survives mutation of the ring it is scanning, which is what makes by-name traversal of a live store workable.
MsgAttrThe @-qualified attribute collection on a field.
MsgDescThe descriptor a manager keeps for the root, and the entry point for adding fields to a store.

P3PmsgBSTR and P2Piomage

String storage, and the packed frame a store becomes when it leaves the process.

  • P3PmsgBSTR holds wide strings inside the heap, length-carrying rather than terminator-scanned.
  • P2Piomage is a packed sync-header frame defined and allocated by Msgcore. It is the on-the-wire shape of a store.
  • This is the seam between the two libraries, and it runs the way round people usually guess wrong: Msgcore defines the frame; TargetCore encrypts it and moves it. The kernel does not define a payload format, and the store does not know what a network is.
  • A message that arrives at a hub handler is therefore not a decoded copy of something. It is the store, as written.

P2Pevent

Events and exceptions, shared with TargetCore rather than duplicated by it.

  • Events are throwable as ordinary C++ exceptions.
  • Events can be attached to a store and carried with it — which is what lets a failure raised inside one process arrive at a caller elsewhere as a catchable object rather than as a timeout.
  • Diagnostic policy is configurable at runtime through a plain text P2Pmsg.cfg beside the host executable, or beside the library itself when the host belongs to somebody else — a bare JVM, for instance. It selects between a message box and a log file.
  • The log file is UTF-8 with no byte order mark on both platforms, opened and closed per entry and serialised across threads. That is a decision taken in the library rather than left to the C runtime, which does not agree with itself across platforms.

Which surface is supported

Msgcore ships three ways in, and they do not carry the same promise. Pick by how your code is built, not by which is most convenient to call.

API surfaces
SurfaceConsumable bySupported
Flat C ABIMsgcore_c.hC, Java through Panama, .NET through P/Invoke, FUSE front ends — anyoneYes. 282 entry points, and the only supported production surface.
C++ classes — P2PmsgMgr.h, P2Pmsg.honly code rebuilt with the same toolsetNo. Pinned to the exact compiler, runtime and debug-iterator model that built the library.
COM / AutomationVBScript, VBA, PowerShell, .NETThrough a separate facade, not from this library.

Each wide-character entry point is paired with a UTF-8 twin, so a cross-platform caller never has to reason about the host's wchar_t width. If you are not compiling Msgcore as part of your own build, use the flat C header.

Two rules a caller has to honour

Neither is visible in a signature, so both are stated here and at the declarations they govern in the shipped header.

  1. Msgcore is not internally synchronised. There is no lock of any kind in the heap. A single store must be serialised by its caller — one critical section per store is the pattern the facades use.
  2. A resolved pointer does not survive a mutation. Growth reallocates the base image; re-resolve from the offset after any operation that can allocate.

One more, about linking

Msgcore ships as a shared library and as a static archive. Every module in one process must reach it the same way — all importing the one shared library, or exactly one module absorbing the archive.

Mixing the two compiles, links, runs, and then corrupts data: an offset minted against one copy's heap resolves against the other's, and there is no link error to warn you. The rule costs nothing to follow and the failure it prevents is very expensive to diagnose, which is why it is on this page rather than in a footnote.

Platforms

Windows is the reference build; Linux is a port of it, and is tested rather than assumed.

Build matrix
PlatformToolchainShape
Windows x64 and Win32Visual Studio 2022 (v143), C++17MFC extension DLL, or static archive
Linux x86-64GCC / Clang through CMake, C++17Shared object, or static archive

The library is licensed under the Apache 2.0 licence. It reads binary images whose headers declare their own extent — which is exactly the shape of parser that rewards hostile input — and it has not been reviewed as a network-facing parser. Findings against the load path are closed and regression-tested, but treat an image from a source you do not control as unsafe to load.

Next: the TargetCore component reference picks the story up at the point a store becomes a frame and gets an address. The walkthrough shows the two libraries assembled into a working hub in eight calls.