ActiveNodes

Hierarchical data processing in a parallel way


Purpose

According to a demand for processing unlimited amounts of data, a concept is needed that is truly unlimited with regard to its data storage and data processing capabilities.

A way for maintaining and processing virtually unlimited amounts of data, as it is currently known, are data hierarchies and operations on data hierarchies. Despite of being aware of a possible existence of much more advanced methods for implementing described objectives, data hierarchies will be taken as the basis for getting to a first implementation of a conceptually unlimited information technology.

Basic concept

In the following, a set of definitions will be given for the elements that this concept is dealing with.


Hierarchy
A hierarchy will be a sequence of nodes where adjacent nodes have a parent-child relationship. There may be one or multiple nodes on each level.

All nodes have a name and an order number on its respective level. A name may be a bit field of appropriate length or a reference to another node, which both represent the identifier as well as the data content of a node. Multiple nodes may have the same name (=data) assigned on a given level, however, they will always have a unique order number.


Top node identifiers
The top node of a hierarchy is supposed to have a name assigned which is unique "in our universe" (universally unique). It is out of scope of this document to describe how to get to a "universally unique" identifier. One possible approach has been developed and described in the "FTLight" specification , e.g. "EKD@JO58nc_Türkenfeld.TimewaveDetector":

The described concept allows for having an unlimited number of distinct hierarchies in our universe, given that unique identifiers can be found for the top nodes of those hierarchies.


Path
A path identifies a node inside a hierachy. It consists of the name of all nodes, starting from the top node down to the node that is referenced. Node names will be connected by a delimiter. In the scope of this document, a 'dot' will serve as a delimiter, e.g. path = UURI.Node_1..Node_N-1.Node_N


Delimiter
Particular elements on a path are said to be separated by implicit delimiters. For special purposes which are explained later, there might be one explicit delimiter added in the end of a path. That delimiter will be a final delimiter which can not be extended by any child nodes. Further, an explicit final delimiter will have no value. One can also say that it represents "emptyness", an empty node.


Link
A subtree of one hierarchy can become a subtree of a second hierarchy. The subtree in the first hierarchy will be identified in the second hierarchy by the UURI of the first hierarchy and a relative path inside that hierarchy.

Subsequently, the referenced subtree becomes an identical instance as in the first hierarchy. When dealing with the subtree either in the first or in the second hierarchy, it will not be possible to distinguish both instances from each other.

A linked node will maintain a list with all nodes that have established a link to that node. This allows for notifications about changes that are sent to all nodes which need to know about it as it will be explained for "Propagating changes across links".


Reference
In opposite to a link, a reference points to a copy of a path, whereas the copy is part of own hierarchy where the node lives that holds a reference to another node. From implementation point of view, a reference looks like a link without maintaining a link list. The special meaning of being a reference results from the way how it is processed, e.g. by an "Active node".

Thus a reference could be seen as a template which starts with the UURI of a hierarchy and which is capable of generating new subtrees in foreign or in own hierarchy as a copy of those template subtrees.


Change Triggered Action
An "active" concept for processing hierarchical data requires taking action whenever some information changes inside a hierarchical data structure. This will be done by an alert from a changed node to an "action" node that is above a changed node in terms of hierarchy.

It is the task of a changed node to find an action node along its path upwards. An "ActiveNodes" hierarchy can expose action nodes on many paths. However, ît has always to have an action node connected to the root node. This is a basic requirement for any live "ActiveNodes" hierarchy.


Propagating changes across links
When a linked node was changed or if a linked node receives a change notification, then it will propagate the change event to all nodes that are linked to the same origin in parallel to forwarding the change locally inside the hierarchy where that change took place. Propagation of a change will be done by an action command as described in the following.


Active node
A subordinate node at position 0 has a special meaning. If it is present and if it has at least Node_N-0-1 connected then the parent node becomes an active node and its child node at position 0 becomes the root of an action command set. An action command set describes all operations that will be performed when the active node is triggered by a change notification.


Action Command Set - destination
Nodes on the first level below the top node of an action command set (its child nodes) will become destination nodes. They contain references to write positions inside same or a foreign hierarchy. A reference points to another node, however, the node itself that holds the reference, preserves its independence and thus it should not be confused with a link where a node becomes identical to the linked node and loses its independence.

Existing information on a destination can be extended or be deleted, dependent on the presence or absence of a delimiter in the end of a Path:
  • Path
existing information on 'Path' will be extended
  • Path<delimiter>
existing Path will be deleted


Action Command Set - source
Each destination position reference has zero, one or multiple source position references. Data from source positions will be transferred to specified destination position whenever the active node is triggered by any local or remote hierarchy changes. If no source was specified, then the destination position will just be notified about a change. This causes the action command set at destination position to be executed. If an action command set is missing at destination position, then the hierarchy will be traveled upwards until an active nodes is found and that active node will be triggered for taking action.

A particular source node can be copied to a destination position or it can be linked to that position, dependent on the presence or absence of a delimiter in the end of a Path:
  • Path
a node will be copied from a source to a destination position
  • Path<delimiter>
a link to a source node will be inserted at destination position


Action Command Set - condition/operation
A source path can be related to a condition which decides, whether a copy/link operation will be performed or not. Conditions will be connected to a source node as child nodes. If no child nodes do exist for a source node then the source node will be copied/linked unconditionally, as it is. In case of multiple child nodes below a source node the copy/link operation will be performed whenever at least one condition evaluates to true.

The rules for evaluating a condition are specific to the type of the action node. Dependent on the action node type there might be a complex hierarchy of nodes connected to a condition node which content in total evaluates to true or false. In particular, an action node might treat condition nodes as references which existence or value might become a component in the evaluation process for a true or false condition.

An action node might also choose to treat the child nodes of a source node as operands instead of conditions. In this case a mathematical operation will be performed with the source node's value as input. The result of that operation will be written to the destination node. Similar to conditions, the type of the action node will decide upon the way how operands will be processed. In particular, an action node might treat operands also as references in order to process the values of multiple source positions into one result which will be written to specified destination position.


Implementation concept


Energy flow

The implementation of a hierarchical data processing will be done based on the energy conservation law. This means that a subspace where all information lives, receives energy from an open energy reservoir and dissipates the same amount of energy that it receives to that same energy reservoir. The information subspace features an appropriate quality of energy which allows to deal with information inside that subspace. All energy outside the information subspace is said to be of insufficient quality of energy for dealing with information of specified type.


Point and distance

We believe that a universal technology must be based on as simple as possible building blocks. Therefore it will be tried to implement a hierarchical data processing on a single concept of "a point and a distance". All subsequent features will be derived from this single base concept.


Order relation

A point and a distance allow for generating an order relation between a parent and multiple client nodes in the following way. A circle around a point P with a radius D will get smaller circles inscribed. The smaller circles are of half the diameter of the initial circle and they all go through its center, except child 0 which is concentric to the initial circle.

The above image shows for example the representation of a parent node along with five child nodes. The described concept allows for assigning arbitrary huge numbers of child nodes to a parent node where the child nodes will always represent an ordered collection of 0..N nodes. For more than 7 child nodes the rotation angle between two adjacent child circles has to be reduced appropriately in order to fit all smaller circles in one rotation inside the initial circle. The image on the right hand side makes the order principle of the geometric presentation on the left hand side obvious.

The energy flow will be defined such that it enters information subspace through a parent node and that it leaves information subspace through a child node. Thus a parent-child relationship can be seen as a continuous energy flow which is powered by an open energy reservoir and which travels partly through an information subspace. On its way it defines a parent node as the place where it enters the information subspace and a child node where it subsequently leaves the information subspace. Since energy in and out have to match, there will be no accumulation of energy in the information subspace. The same amount of energy that enters information subspace at parent node is leaving it at child node. Conservation of energy is preserved.


Assignment relation

Multiple nodes may be assigned to a selected node which becomes the representative of all the other nodes. The principle is shown on the following image which shows an assignment relation inside an information hierarchy on the left hand side. On the right, the essential meaning of the principle is shown by a graph that references a multitude of nodes by a single representative. Later on we will see that a "representative" may be a path, a word or a single letter or any other item which may refer or point to the meaning of something (semantic).

The energy flow for an assignment will involve a reflector (mediator) node in addition to a flow-in node (parent) and a flow-out node (representative). The mediator node knows about both, its parent node and its representative and thus it is capable of establishing an energy flow from its parent to its representative node. One could also think about a mediator node as if it was acting as an energy reflector that re-directs an energy flow from its parent towards its representative node. Again, the amount of energy that enters the information subspace at parent node will leave that subspace at representative node and therefore energy conservation will be preserved for assignment relations as well.

In internal implementation of child references, we will see that a child_N will also be a mediator between child_N-1 and child_N+1. In particular, child-0 will be a mediator between the parent node of all childs on this level and a subsequent node, usually for child-1. Thus the energy flow between a parent node and the child_N node will involve multiple mediator nodes, as many as are present on this level as child-0...child_N-1 node. Nevertheless the same principle applies as described before, where the energy enters the information subspace at parent node and it leaves for energy reservoir at child_N node and conservation of energy is preserved also in this case.

The root node is a special case with regard to energy flow. It is the only node in a hierarchy which will have itself assigned as the parent node. Thus when it gets a representative assigned, energy will flow in through the root node, it will be reflected by the same root node and subsequently it will fly out through the representative.

The representative of a root node in a hierarchy is the UURI (universally unique resource identifier) of a hierarchy as it was previously defined. The way how a UURI is assigned makes it possible to generate a sufficiently unique identifier by selecting a long and complex path as the representative for a root node.


Implementation design


Node

A node will maintain four references to other nodes with the following meanings:


Root node

A node will be recognized as a root node whenever its parent reference points to the node itself. The reference to a next node may point to a next root node in this case, thus connecting all root nodes in a chain. A first root node is referenced by a global pointer and after the last root node in the chain, NULL is assigned to the Next pointer.


Active node

An active node will have a reference to an action table in addition to a node's general references.


Non-active

A non-active node will be identified by an empty command set at child-0. The Child reference of child-0 points to the node itself in this case.

In a second scenario, a non-active node might have a child node-0-0 assigned, however that child node-0-0 would not have any siblings assigned to its Next pointer.


Link

A link is a special case where value and child references will be taken from a linked node. A node will be recognized as a link whenever the value reference points to a parent node.


Delimiter

A delimiter is implemented as a link to a node itself. Since a delimiter's child reference points back to current node, it will not be possible to add any child nodes. This is intended because an explicit delimiter represents a final end point of a path.


Value

A basic value will be represented by the position that a node occupies in the child node chain of its parent. The value reference will point to the node itself in this case.

Complex values will be implemented by a chain of simple/complex values. In this case the value reference points to the last node in the chain of nodes that represent a value. The chain will be followed backwards until the root node is reached. The value of the root node will not be taken into account.


Initial values


Interface design

An application can get acces to ActiveNodes by first acquiring a mutex and subsequently sending a request. Actual data exchange will take place by data (value, =bit field) sent to a specified node of an ActiveNodes hierarchy and by receiving response data (value, =bit field) from those nodes with which the application has registered.

The single access point concept for ActiveNodes aims at robustness in communication as well as at access control. Robustness is enhanced by sending a plain data token (request) to the guard of an ActiveNodes hierarchy. The guard process first checks the structure of each received request. In case the request structure is according to its requirements, the guard will try to get back to the application. This procedure will confirm that ActiveNodes and an application are able to exchange data successfully. Further the opening process may involve an authorization procedure as well as a negotiation for data encryption for all subsequent traffic.

After a succeccful opening process an application might register for downstream data feeds or it can apply for upstream data access. In a basic access scheme, a request may contain already actual data to be sent to a node or a request for receiving data from a node without registering for downstream feeds and without applying for upstream data access.



//////////////////////////////////////////////////////////////////////////////
//
// ANodes.h: Declaration of an ActiveNodes module
//
//////////////////////////////////////////////////////////////////////////////
//
// Author:     Eckhard Kantz
// Website:    wegalink.eu
//
//////////////////////////////////////////////////////////////////////////////
/* 
This is FREE software 

Permission is hereby granted, free of charge,  to any person obtaining  a copy 
of this software and associated documentation files (the "Software"),  to deal 
in the Software without restriction, including without limitation  the  rights 
to use,  copy,  modify,  merge,  publish,  distribute, sublicense, and/or sell 
copies  of  the  Software,   and  to  permit  persons  to  whom  the  Software 
is furnished to do so, subject to the following conditions: 

There are no conditions imposed on the use of this software.

THE SOFTWARE IS PROVIDED "AS IS",  WITHOUT  WARRANTY  OF ANY KIND,  EXPRESS OR
IMPLIED,  INCLUDING  BUT  NOT  LIMITED  TO  THE  WARRANTIES OF MERCHANTABILITY,
FITNESS  FOR  A  PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS  OR  COPYRIGHT  HOLDERS  BE  LIABLE  FOR  ANY CLAIM,  DAMAGES OR OTHER
LIABILITY,  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,  ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN  THE
SOFTWARE.
*/

#ifndef ANodesH
#define ANodesH

/* Compiler dependent includes and defines */
#include "types.h"

/***********************************************************************
*  General data types, relevant for interfacing to ActiveNodes
***********************************************************************/

/** Timestamp structure
 *  A timestamp structure allows for specifying a send and a receive
 *  time, each consisting of a ticks and a frequency value. Whenever
 *  required, those values can be converted into absolute or relative
 *  time values.
 *
 *  Because of a usually short travel time from sender to receiver, it
 *  will be possible to determine the relation to UTC on both sides,
 *  sender and receiver unambiguously, given that both sides maintain
 *  an accurate clock that is synchronized with UTC.
 */
typedef struct
{
  __int64 SendTicks;
  __int64 SendFrequency;
  __int64 ReceivedTicks;
  __int64 ReceivedFrequency;

} Timestamp;

/** Value structure 
 *  A value represents a bit field of an extrem range. It may be as
 *  small as a single bit for representing boolean values. On the other
 *  hand it may represent a bit field of unthinkable huge length, as for
 *  example "all atoms in the universe", or the like. 
 *
 *  The extrem dynamic range is accomplished by a Size feature which
 *  serves as an exponent base two for a DataBits variable.
 *
 *  Creation and delivery of a value is tracked by timestamps because of
 *  the main purpose of a Value for transferring data from a sender to a 
 *  receiver. One side may be a remote one why it is important to track
 *  the travel time from sender to receiver.
 */
#define SIZE_POINTER sizeof(unsigned char *)
typedef struct
{
  unsigned char *DataBytes;  /* pointer to a DataBytes field          */
  unsigned char *DataBits;   /* pointer to a DataBits field           */
  Timestamp *Time;           /* pointer to a timestamp structure      */
  unsigned char Magic[SIZE_POINTER];
                             /* size of bit field length [bits]       */
                             /* 00000000: 2^0 =   1 bit               */
                             /* 00000001: 2^1 =   2 bits              */
                             /* 00000011: 2^2 =   4 bits              */
                             /* 00000111: 2^3 =   8 bits              */
                             /* 00001111: 2^4 =  16 bits              */
                             /* 00011111: 2^5 =  32 bits              */
                             /* 00111111: 2^6 =  64 bits              */
                             /* 01111111: 2^7 = 128 bits              */
                             /* 11111111: 2^8 = 256 bits              */
#define ACTIVE_NODES_MAGIC          0xFEDCBA9876543200 
#define ACTIVE_NODES_MASK           0xFFFFFFFFFFFFFF00
#define ACTIVE_NODES_MAGNITUDE      0x00000000000000FF
// Coding for magnitudes of bit field lengths
#define ACTIVE_NODES_MAGNITUDE_1    0x0000000000000000
#define ACTIVE_NODES_MAGNITUDE_2    0x0000000000000001
#define ACTIVE_NODES_MAGNITUDE_4    0x0000000000000003
#define ACTIVE_NODES_MAGNITUDE_8    0x0000000000000007
#define ACTIVE_NODES_MAGNITUDE_16   0x000000000000000F
#define ACTIVE_NODES_MAGNITUDE_32   0x000000000000001F
#define ACTIVE_NODES_MAGNITUDE_64   0x000000000000003F
#define ACTIVE_NODES_MAGNITUDE_128  0x000000000000007F
#define ACTIVE_NODES_MAGNITUDE_256  0x00000000000000FF
// Boundaries for length values upto 32 bits
#define ACTIVE_NODES_BOUNDARY_1     0x0000000000000002
#define ACTIVE_NODES_BOUNDARY_2     0x0000000000000004
#define ACTIVE_NODES_BOUNDARY_4     0x0000000000000010
#define ACTIVE_NODES_BOUNDARY_8     0x0000000000000100
#define ACTIVE_NODES_BOUNDARY_16    0x0000000000010000
#define ACTIVE_NODES_BOUNDARY_32    0x0000000100000000

} Value;

/** ANodeStream
 *  Information that is sent from a client to an ActiveNodes hierarchy
 *  or vice versa.
 *
 *  The ActiveNodes server will delete an ANodesStream when the client 
 *  signaled that it is not needed anymore by writing zero to the
 *  ClientAlert handle.
 */
typedef struct
{
  /*  Signaling: inform client about new DownStream data, respectively
   *  let the ActiveNodes hierarchy know about new upstream data.
   */
  HANDLE ClientAlert;      /* event handle in client process      */
  HANDLE ANodesAlert;      /* event handle in ActiveNodes process */

  /* UURI, relative Path and actual Data */
  Value *UURI;
  Value *Path;
  Value *Data;

  /* Access synchronization */
  bool ANodesStreamBusy;

} ANodesStream;

/** AppForm
 *  An application form is provided by an ActiveNodes hierarchy to a
 *  program that requests access to the hierarchy. The AppForm enables
 *  the client program to apply for establishing DownStream and UpStream 
 *  channels.
 *
 *  An AppForm is also needed in case of a client program that intends 
 *  to run a burst contact against an ActiveNodes hierarchy. 
 *  A burst contact may be useful in case of a considerable delay in
 *  communication between a client and an ActiveNodes hierarchy, e.g. 
 *  when communicating from a base station on Earth to a space probe or 
 *  vice versa.
 *
 *  The ActiveNodes server will delete an AppForm when the client 
 *  signaled that it is not needed anymore by writing zero to the
 *  ClientAlert handle.
 */
typedef struct
{
  /* Signaling: Informing an ANodesGate about AppForm submitted */
  HANDLE ClientAlert;          /* event handle in client process      */
  HANDLE ANodesAlert;          /* event handle in ActiveNodes process */

  /* Security section */
  Value *Challenge;       /* data to be encrypted by the peer         */
  Value *Response;        /* data that has been encrypted by the peer */

  /* Data section */
  Value *DownStreamList;  /* request list for downstream data feeds   */
  Value *UpStreamList;    /* request list for upstream data access    */

} AppForm;

/** ActiveNodesRequest
 *  An application will have to issue an ActiveNodesRequest to an
 *  ActiveNodesGate in order to obtain access to functionality of an 
 *  ActiveNodes hierarchy.
 *
 *  From a system robustness point of view, a successful acquisition
 *  of an ActiveNodesGate's mutex and further writing a request would 
 *  confirm that a client has valid read/write access to ActiveNodes' 
 *  process memory.
 *
 *  An ActiveNodesGate will first evaluate a client's certificate. It
 *  is allowed and supposed to discard a request silently in case of
 *  an invalid certificate or in case of any other reasons that would
 *  prevent from establishing a communication to that client.
 *
 *  In case of a positive validation result, an ActiveNodesGate will
 *  generate an application form and will send that AppForm back to
 *  the client. This will confirm on success that the ActiveNodes 
 *  process and the calling application are able to successfully 
 *  exchange information with each other.
 *
 *  Further, an application or the ActiveNodes hierarchy might request 
 *  for encrypting all data transfer that will follow, after the 
 *  opening procedure for communication has been passed successfully.
 *
 *  The ActiveNodes server will delete an ActiveNodesRequest when the 
 *  client signaled that it is not needed anymore by writing zero to the
 *  ClientAlert handle.
 */
typedef struct
{
  /* Signaling: Informing a client about AppForm availability */
  HANDLE ClientAlert;         /* event handle in client process      */
  HANDLE ANodesAlert;         /* event handle in ActiveNodes process */

  /* Authorization: connects an identity to a public key */
  Value *ClientCertificate;
  Value *ANodesCertificate;

  /* Applying for downstream feeds/upstream access */
  AppForm *Form;

} ActiveNodesRequest;

/** ActiveNodesGate
 *  An ActiveNodesGate allows for registering for downstream data feeds 
 *  going from an ActiveNodes hierarchy to an application and to apply   
 *  for upstream access to specified ActiveNodes paths by an application. 
 *
 *  In a basic access scheme, an application might communicate solely 
 *  over the gate of an ActiveNodes hierarchy by each time establishing
 *  all needed UpStreams and DownStreams for a one-time communication. 
 *
 *  That type of communication might be applicable in case of a 
 *  considerable delay on the way from a client to an ActiveNodes 
 *  hierarchy where the advantage of a fast communication by persistent
 *  UpStreams and DownStreams disappears.
 *
 *  A client is supposed to always read and write all data based on an
 *  ActiveNodes hierarchy's process ID. Therefore the process ID of an 
 *  ActiveNodes hierarchy is published which allows clients to use it 
 *  for all access functions.
 */
typedef struct
{
  ActiveNodesRequest *ANodesRequest;            /* a client's request */

  HANDLE Access;    /* mutex to be acquired before placing a request  */
  HANDLE Alert;     /* event to be signaled when a request was placed */

  int ProcessID;    /* to be checked for handle/memory access reasons */

} ActiveNodesGate;

/* Common global access to an ActiveNodesGate and to memory management*/
#ifdef ACTIVE_NODES_IMPLEMENTATION
  ActiveNodesGate *GlobalANodesGate = NULL;
  void **GlobalANodesMemory = NULL;
#else
  extern ActiveNodesGate *GlobalANodesGate;
  extern void **GlobalANodesMemory;
#endif

/***********************************************************************
*  Internal data types, relevant for implementation of ActiveNodes
***********************************************************************/

/** Node structure
 *  A node holds references to four other nodes
 *   - Value
 *   - Parent
 *   - Child
 *   - Next (child)
 */
typedef struct Node Node;
typedef struct Node
{
  Node *Value;
  Node *Parent;
  Node *Child;
  Node *Next;
};

/** ActiveNodes global root
 *  A pointer to a first root node will be an entry point to a chain of
 *  root nodes.
 */
#ifdef ACTIVE_NODES_IMPLEMENTATION
  Node *ANodes = NULL;
#else  
  extern Node *ANodes;
#endif

/** ActionTable
 *  An action table holds function pointers to a well defined set of 
 *  actions which allow for operating an ActiveNodes hierarchy.
 *  It is assumed that all nodes below a node with an action table 
 *  ("action node") belong to the same implementation as the action 
 *  node itself. This assumption allows for applying functions related 
 *  to an action node also to all nodes that belong to the subtree below 
 *  that action node when processing any change request in the hierarchy.
 */
typedef struct ActionTable ActionTable;

/** ActionWorkspace
 *  An action workspace provides for individual instance data (member 
 *  variables) of every ActionNode instance whereas an ActionTable holds 
 *  a unique set of functions (methods) for a given implementation of an 
 *  ActiveNodes hierarchy.
 */
typedef struct ActionWorkspace ActionWorkspace;

/** ActionWorkspaceRoot
 *  A root action workspace is an extended action workspace. It allows 
 *  for memory bookkeeping of the nodes inside an hierarchy additionally.
 */
typedef struct ActionWorkspaceRoot ActionWorkspaceRoot;

/** ActiveNode structure
 *  An active node has a reference to an action table and a workspace 
 *  in addition to a node's general references.
 */
typedef struct
{
  Node *Value;
  Node *Parent;
  Node *Child;
  Node *Next;
  ActionTable *Action;
  ActionWorkspace *Workspace;

} ActiveNode;

/** RootNode structure
 *  A root node is basically an active node with the only difference that
 *  it maintains an extended workspace for bookkeeping purposes inside its
 *  hierarchy.
 */
typedef struct
{
  Node *Value;
  Node *Parent;
  Node *Child;
  Node *Next;
  ActionTable *Action;
  ActionWorkspaceRoot *Workspace;

} RootNode;

/** Actions
 *  The following well defined set of operations allows for operating 
 *  an ActiveNode hierarchy. 
 *  A specific implementation of ActiveNodes has to provide for actual
 *  functionality of those operations.
 */

/* Identifier of an ActiveNodes implementation (including version) */
typedef Node * (__stdcall *Action_getIdentifier)();

/* Maintaining a hierarchy */
typedef Node * (__stdcall *Action_putValue)(Node*, Value*);
typedef Node * (__stdcall *Action_copyNode)(Node*, Node*);
typedef Node * (__stdcall *Action_linkTree)(Node*, Node*);
typedef Node * (__stdcall *Action_deletePath)(Node*);

/* Notify an active node about changes in its subtree */
typedef Node * (__stdcall *Action_notifyActiveNode)(Node*);

/* Value access methods */
typedef Value * (__stdcall *Action_readValue)(Node*);

/* Navigation methods */
typedef Node * (__stdcall *Action_getValue)(Node*);
typedef Node * (__stdcall *Action_getParent)(Node*);
typedef Node * (__stdcall *Action_getChild)(Node*);
typedef Node * (__stdcall *Action_getNext)(Node*);
typedef Node * (__stdcall *Action_getRoot)(Node*);

/* Maintaining Nodes instances */
typedef Node * (__stdcall *Action_createRoot)(Node*);
typedef Node * (__stdcall *Action_createNode)(bool Active);
typedef void (__stdcall *Action_deleteNode)(Node*);

/* ActionTable */
struct ActionTable
{
  /* Identifier of an ActiveNodes implementation (including version) */
  Action_getIdentifier getIdentifier;

  /* Maintaining a hierarchy */
  Action_putValue putValue;
  Action_copyNode copyNode;
  Action_linkTree linkTree;
  Action_deletePath deletePath;

  /* Notify an active node about changes in its subtree */
  Action_notifyActiveNode notifyActiveNode;

  /* Value access methods */
  Action_readValue readValue;

  /* Navigation methods */
  Action_getValue getValue;
  Action_getParent getParent;
  Action_getChild getChild;
  Action_getNext getNext;
  Action_getRoot getRoot;

  /* Maintaining Nodes instances */
  Action_createRoot createRoot;
  Action_createNode createNode;
  Action_deleteNode deleteNode;
};


/***********************************************************************
*  ActiveNodes interface functions and return codes
***********************************************************************/
typedef enum
{
  ANODE_OK                        =  0,
  ANODE_ERROR                     = -1,
  ANODE_MEMORY_MANAGEMENT_FAILED  = -2,
  ANODE_MEMORY_MANAGEMENT_DOWN    = -3,
  ANODE_INVALID_REQUEST           = -4,
  ANODE_INVALID_FORM              = -5,
  ANODE_INVALID_PARAMETER         = -6,
  ANODE_INVALID_VALUE             = -7,
  ANODE_GATE_CREATION_FAILED      = -8,
  ANODE_GATE_INVALID_STATE        = -9,
  ANODE_GATE_ACCESS_TIMEOUT       = -10,
  ANODE_GATE_THREAD_FAILED        = -11,
  ANODE_CLIENT_NOT_FINISHED       = -12,

} ANODE;

/** BurstRequest
 *  The structure comprises all data that is needed for running a 
 *  burst request (synchronous request) against an ActiveNodes
 *  hierarchy.
 */
typedef struct
{
  /* Application's identification and public encryption key */
  unsigned char *Certificate;
  uint64 CertificateLength;
  /* Maximal waiting time for downstream [s] */
  float DownStreamTimeout;
  /* Downstream data from ActiveNodes to an application */
  unsigned char *DownStreamUURI;
  unsigned char *DownStreamPath;
  unsigned char **DownStreamData;
  uint64 DownStreamUURILength;
  uint64 DownStreamPathLength;
  uint64 *DownStreamDataLength;
  /* Upstream data from application to ActiveNodes */
  unsigned char *UpStreamUURI;
  unsigned char *UpStreamPath;
  unsigned char *UpStreamData;
  uint64 UpStreamUURILength;
  uint64 UpStreamPathLength;
  uint64 UpStreamDataLength;

} BurstRequest;

/** submitANodesRequest.
 *  A burst request will run against an ActiveNodes hierarchy. The 
 *  request consists of sending upstream data and of requesting for
 *  downstream response data. 
 *
 *  Input data will be sent to an appropriate node in the ActiveNodes 
 *  hierarchy that can handle a received http request. A http response 
 *  will be generated and delivered to application by a downstream.
 */
ANODE submitANodesRequest( BurstRequest *Burst );

/** createANodesStream.
 *  An ANodeStream structure will be created if it does not exist.
 *  Subsequently it will be filled in with received ANodeStream data.
 *  Further, synchronization means will be added for communicating
 *  seamlessly with the ActiveNodes hierarchy.
 */
ANODE createANodesStream( ActiveNodesGate *ANodesGate,
                          ANodesStream **Stream,
                          unsigned char *UURI,
                          unsigned char *Path,
                          unsigned char *Data,
                          uint64 UURILength,
                          uint64 PathLength,
                          uint64 DataLength );

/** freeANodeStream.
 *  The ANodeStream will be freed by closing the ClientAlert and 
 *  clearing its entry to zero. This will be recognized by an 
 *  ActiveNodes hierarchy that the stream is no longer in use and 
 *  thus it can be deleted.
 */
ANODE freeANodeStream(ANodesStream *Stream);

/** deleteANodeStream.
 *  Memory occupied by a Stream will be released. Further the pointer
 *  to the deleted ANodesStream will be cleared to zero.
 */
ANODE deleteANodesStream(ANodesStream **Stream);

/** clearANodeStream.
 *  The data content of an ANodeStream will be cleared.
 */
ANODE clearANodesStream(ANodesStream *Stream);

/** extendStreamList.
 *  A list (an array) of streams will be extended by a further stream.
 *  In case the list (the array) does not exist, it will be created.
 */
ANODE extendStreamList(Value **ANodeStreamList, ANodesStream *Stream);

/** deleteStreamList.
 *  Memory occupied by a StreamList will be released. Further the 
 *  pointer to the stream list will be cleared to zero.
 */
ANODE deleteStreamList(Value **StreamList);

/** createValue. 
 *  A Value structure will be filled with received data. If it does not
 *  exist then it will be created.
 */
ANODE createValue(Value **Val, unsigned char *DataBytes, uint64 DataBits);

/** deleteValue.
 *  Memory occupied by a Value will be released and the Value pointer 
 *  will be cleared to NULL.
 */
ANODE deleteValue(Value **Val);

/** evaluateValue.
 *  A value structure will be evaluated and its components will be
 *  returned.
 */
ANODE evaluateValue(Value *Val, unsigned char **DataBytes,
                    uint64 *DataBits, Timestamp **Time);

/** unloadData.
 *  Data will be copied from a Value structure to memory which will
 *  be allocated accordingly to the size of the data.
 */
ANODE unloadData(Value *Val, unsigned char **DataBytes, uint64 *DataBits);

/** setDataBits.
 *  The DataBits component of a Value will be generated.
 */
ANODE setDataBits(Value *Val, uint64 DataBits);

/** getDataBits.
 *  The DataBits component of a Value will be decoded. Prior to 
 *  decoding data bits, a validity check will be performed based on 
 *  a magic value that was inserted into Value on creation.
 */
ANODE getDataBits(Value *Val, uint64 *DataBits);

/** createTimestamp.
 *  A timestamp will be created from current ticks and frequency
 *  for sending out data to the peer.
 */
ANODE createTimestamp(Timestamp **Time);

/** stampTimestamp
 *  The receive portion of a Timestamp will be adjusted to 
 *  current ticks and frequency.
 */
ANODE stampTimestamp(Timestamp *Time);

/** requestAppForm.
 *  A client requests for permission for sending an application form
 *  to an ActiveNodes server system. An authorization is included
 *  which requires a client to provide for a certificate.
 */
ANODE requestAppForm(ActiveNodesGate *ANodesGate,
                     ActiveNodesRequest **Request,
                     Value *Certificate);

/** submitAppForm.
 *  Recently prepared UpStreams and DownStreams will be submitted to 
 *  an ActiveNodes hierarchy for processing. Subsequently, the
 *  application has to wait for receiving a response.
 */
ANODE submitAppForm(ActiveNodesRequest *Request);

/** freeAppForm.
 *  An AppForm's ClientAlert will be cleared to zero in order to 
 *  indicate that the AppForm is no longer in use. If ClientAlert
 *  was different from ANodesAlert then its handle will be closed.
 */
ANODE freeAppForm(AppForm *Form);

/** deleteAppForm.
 *  A previously requested AppForm will be released and thus it will
 *  be deleted along with deleting all structures that it consists of.
 */
ANODE deleteAppForm(AppForm **Form);

/** freeANodesRequest.
 *  An ANodesRequest's ClientAlert will be cleared to zero in order  
 *  to indicate that the ANodesRequest is no longer in use. If its
 *  ClientAlert was different from ANodesAlert then it will be closed.
 */
ANODE freeANodesRequest(ActiveNodesRequest *Request);

/** deleteANodesRequest.
 *  A request along with all structures that it consists of will be
 *  deleted.
 */
ANODE deleteANodesRequest(ActiveNodesRequest **Request);

/*----------------------------------------------------------------------
 * The following functionality will be provided by an ActiveNodes server 
 *----------------------------------------------------------------------
 */

/** Resource tracking
 *  The following resource allocation/deallocation will be tracked
 *  inside the memory management system
 */
typedef enum
{
  RESOURCE_TYPE_MEMORY      = 0,
  RESOURCE_TYPE_THREAD      = 1,
  RESOURCE_TYPE_VALUE       = 2,
  RESOURCE_TYPE_STREAM      = 3,
  RESOURCE_TYPE_APPFORM     = 4,
  RESOURCE_TYPE_REQUEST     = 5

} ResourceType;

/** trackResource
 *  A tracking will count the allocation/deallocation of several
 *  system resources.
 */
ANODE trackResource(ResourceType Type, bool Alloacated);

/** Memory.
 *  Allocation and deallocation of memory.
 */
ANODE Memory(void** DataBytes, uint64 DataLength);

/** shutdownMemoryManagement
 *  The memory management system will be shutdown. Normally all allocated
 *  memory chunks should have been released at this point. It will be
 *  reported as error if this is not the case.
 */
ANODE shutdownMemoryManagement();

/** getActiveNodesGate.
 *  A pointer to an ActiveNodesGate will be returned to the application.
 *  An new ActiveNodesGate will be created in case it does not exist yet 
 *  and all needed synchronization means will be supplied. Further a 
 *  processing thread will be started that further deals with requests 
 *  that arrive on the ActiveNodesGate.
 *
 *  LIVETIME: The sole purpose of an ActiveNodes hierarchy is serving
 *            clients for DownStream and UpStream data. When the last
 *            client has disconnected there is no reason for further
 *            work of an ActiveNodes hierarchy. Therefore it will be
 *            shutdown when the last client has gone.
 */
ANODE getActiveNodesGate(ActiveNodesGate **ANodesGate);

/** serveANodesGate.
 *  This is a thread function that serves all ANodes requests for the 
 *  life time of an ANodes hierarchy. It finishes by its own when the
 *  last ANodes hierarchy has disappeared from the root node chain.
 */
DWORD WINAPI serveANodesGate(void *Context);

/** processAppForm.
 *  This is a thread function that processes requests which have been
 *  sent against an ANodesGate in an application form. The thread will
 *  wait for more requests from the same AppForm until a client shuts
 *  down communication by clearing its event handle in the AppForm.
 */
DWORD WINAPI processAppForm(void *Context);

/** serveUpStream.
 *  A series of UpStream requests will be served in a thread function.
 */
DWORD WINAPI serveUpStream(void *Context);

/** serveDownStream.
 *  A series of DownStream requests will be served in a thread function.
 */
DWORD WINAPI serveDownStream(void *Context);

/** processUpStream.
 *  A single UpStream request will be processed
 */
ANODE processUpStream(ANodesStream *UpStream);

/** processDownStream.
 *  A single DownStream request will be processed
 */
ANODE processDownStream(ANodesStream *DownStream);

/*----------------------------------------------------------------------
 * System diagnostics
 *----------------------------------------------------------------------
 */

/* All diagnostics information will be assigned to one of the following
 * log level
 */
typedef enum
{
  LOG_OFF      = 0,
  LOG_FATAL    = 1,
  LOG_ERROR    = 2,
  LOG_WARN     = 3,
  LOG_INFO     = 4,
  LOG_DIAG     = 5,
  LOG_DEBUG    = 6,
  LOG_ALL      = 7

} LogLevel;

/* Overall system log level and start time*/
#ifdef ACTIVE_NODES_IMPLEMENTATION
  LogLevel SysLogLevel = LOG_DIAG;
  uint64 AppStartTicks = 0;
#else  
  extern LogLevel SysLogLevel;
  extern uint64 AppStartTicks;
#endif

/** logMessage.
 *  A log message will be generated from provided text and numerical 
 *  data and it will be sent to log output.
 */
void logMessageInt(LogLevel MsgLogLevel, char *Msg, Timestamp *Time,int Val);
void logMessage(LogLevel MsgLogLevel, char *Msg, Timestamp *Time,void *Val);

/** Error.
 *  An error code along with a context will be converted into a log 
 *  message.
 */
ANODE Error(ANODE ErrCode, char* Context, void *Val);




#endif



Created: 2008-09-15 by Eckhard Kantz