Messages

Messages sind unabhängig von Plattform und Programmiersprache. Im Wesentlichen sind sie eine Menge aus Schlüssel und Wert-Paaren, wobei die Werte aus einem Pool von Typen stammen müssen.

Messages lassen sich erst einmal in zwei Bestandteile teilen: den Nachrichten-Umschlag (Envelope) und der Nutzlast (einem oder mehrere Records).

Der Envelope

Der Umschlag sorgt dafür, das die Nachricht zu ihrem Ziel kommt. Er hat eine ganze Reihe von Datenfeldern, mit denen die Reise konfiguriert werden kann.

Der Record

Die Nutzlast besteht aus den Daten, die übermittelt werden sollen. Meist befindet sich dazu ein einzelner Record in der Message. Records enthalten eine Record-ID vom Typ IId. Sie entscheidet beim Empfänger, von welchem Message-Handler die Nachricht bearbeitet wird.

Die Daten selber verstecken sich in typisierten Slots. Slots wiederum bestehen aus einem Schlüssel sowie dem Datenwert.

Folgende Slot-Typen werden unterstützt:

Typ Beschreibung
BYTE Ein byte (byte).
BYTEARRAY Ein byte Array (byte[]).
CHAR Ein Character (char).
CHARARRAY Ein Character Array (char[]).
BOOLEAN Ein Boolean (boolean).
BOOLEANARRAY Ein Boolean Array (boolean[]).
SHORT Ein Short (short).
SHORTARRAY Ein Short Array (short[]).
INT Ein Integer (int).
INTARRAY Ein Integer Array (int[]).
LONG Ein Long Integer (long).
LONGARRAY Ein Long Integer Array (long[]).
FLOAT Ein Float (float).
FLOATARRAY Ein Float Array (float[]).
DOUBLE Ein Double (double).
DOUBLEARRAY Ein Double Array (double[]).
STRING Ein String (String, im Stream UTF-8).
STRINGARRAY Ein String Array (String[], im Stream UTF-8).
ID Eine ID (IId).
IDARRAY Ein ID Array (IId[]).
NODEID Eine NODE-ID (INodeID).
NODEIDARRAY Ein NODE-ID Array (INodeID[]).
TARGETADDRESS Eine Target Adresse (ITargetAddress).
TARGETADDRESSARRAY Ein Target Address Array (ITargetAddress[]).
UUID Ein UUID (UUID).
UUIDARRAY Ein UUID Array (UUID[]).
BITFIELD Ein Bit Field (CBitField).
RECORD Ein Message Record (CRecord).
RECORDARRAY Ein Message Record Array (CRecord[]).
MESSAGE Eine Message (IMessage).
OBJECT Ein Object (Object - nicht routebar, nur lokal verwendbar).

Die Slot-Keys

Die Slot-Keys bestehen aus zwei IId-Objekten. Dieser Slot-Key wird auch im Datapool verwendet. Zwei IDs sind flexibler als eine. Die Verwendung von Schemata wie in der Windows™-Registry (path+key=value) ist damit genauso möglich wie z.B. (typ+id=value) oder (id+subId=value). Wer mit einer ID auskommt, benutzt eben nur diese eine ID. Die andere ID bleibt dann leer und kostet im Stream lediglich 1 Byte.

Warum dieses Format?

devel.one ist generell unabhängig von der Programmiersprache. So gibt es (noch nicht als Produkt erhältlich) Derivate in anderen Sprachen wie C und C++, welche mit den Daten umgehen müssen. Die Welt ist etwas größer als JAVA™. Doch selbst wenn es nur JAVA™ gäbe: Wir wollen kein träges XML verschicken, da dieses wieder geparst werden müsste. Wir wollen auch nicht serialisieren, da wir kleine und schnelle Messages bevorzugen. Und wir können auch nicht erwarten, das am anderen Ende der Leitung unsere Interfaces bekannt sind. Und selbst, wenn die Interfaces bekannt wären, hätten wir wieder das Problem, das unterschiedliche Versionsstände kollidieren würden.

Mit anderen Worten: die Slot-Messages sind die Lösung und die Stärke von devel.one.

Im Stream - also auf dem Weg zwischen zwei devel.one-NODES - liegen die Daten der Slots im Minimalformat vor. Ein Integer umfasst also 4 Bytes, ein Byte natürlich 1 Byte usw. Dazu kommt ein komprimierter Integer für den Slot-Typ. Für Längenangaben, Typen etc. werden diese Integer verwendet, in deren ersten beiden Bits die Anzahl der verwendeten Bytes codiert sind. Die Integer haben alse ene Länge von 1-4 byte und transportieren zwischen 8-30 bit payload. Weniger geht nicht. Ähnlich sieht es bei den Slot-Keys wie auch bei dem Message-Envelope aus. Der meisten Felder des Envelopes bestehen aus Bits in einem Bitfeld. Nur die Adressen für Absender und Empfänger sind voluminöser, da hier 17 Bytes für die UUIDs der NODE-IDs verwendet werden.

Das Parsen einer gestreamten Message ist dadurch blitzschnell und resourcen-arm, ebenso wie das Streamen selbst. Das sorgt für die beste Ausnutzung der vorhandenen Bandbreite und für die hohe Performance. Zudem sind wir dadurch plattformunabhängig und können das Framework leicht in anderen Programmiersprachen implementieren.

Das System kann einfach durch andere Slot-Typen ergänzt werden, da neue Slot-Klassen registriert werden können. Dabei ist jedoch zu beachten, dass die Verwendung von eigenen Typen die Interoperabilität mit anderen Tools stark einschränkt. Zumindest für den Austausch mit fremden Tools sollte man sich also auf die eingebauten Typen beschränken. Wir werden die Typen ganz sicher erweitern, und wer noch einen Vorschlag hat, sollte den doch einfach äußern ;-)

Warum ist es möglich, mehrere Records in eine Message zu stecken?

Der Envelope hat einen gewissen Overhead, da insbesondere die Adressen Platz einnehmen. Daher ist es möglich, mehrere Records auf einen Rutsch an ein Remote Target zu verschicken. Auf der Empfänger-Seite wird das nicht bemerkt, da der Message-Header mit jeweils einem einzelnen Record an den Message-Handler gereicht wird.

In der lokalen Instanz sind nahezu 100% aller Messages Single-Record-Nachrichten.