# Introduction to eXtremeDB Active Replication Fabric

> As explained in the eXtremeDB Active Replication Fabric page, Active Replication Fabric is an eXtremeDB-based foundation for distributed IoT applications. And, as further explained in The IoT Challenges page, the volume of data collection points (edge devices), the constrained resources and CPU power of these devices, and the sporadic nature of connectivity between the devices and backend processors are the driving considerations for the Active Replication Fabric distributed architecture.

> Active Replication Fabric applications can apply advanced analytics to IoT data enabling businesses to discover usage patterns, identify weaknesses in connected devices and, in the end, distribute available resources, technological and financial, to help create better connected products.

> ## Theory of operation

> Functionally, data in the IoT environment can be put into three broad categories: edge devices, where the data is collected, routers and servers, where the data is analyzed. Edge devices capture or generate data, may do some initial filtering, and make sure that the data is safe for some period of time before they transmit the data to servers for further processing.

> IoT routers can form one or more additional layers of nodes between servers and edge devices. The IoT topology looks like a tree where the server is the root, the devices are the leaves, and the routers are the inner nodes. Each node in this tree has a level (a 2-byte integer): the server always has level = 1, the level of devices is 65535 ( = 0xFFFF ) and routers have a level between 2 and 65534. The level of the router defines its position in the tree - the smaller the level value, the "closer" the node is to the server. The level of the routers (and their relative position) can be changed at runtime, but the basic type (device, server or router) cannot be changed after the database creation.

> As well as server and devices, each router must have a unique agent ID. Note that the server always has fixed `agent_id = 1`. UP/DOWN tables on the server have an automatically generated field `agent_id`. For UP tables it denotes the node that created the record. For DOWN tables it denotes the receiver of the row created by the server. Routers have two generated fields in their UP/DOWN tables : `src_agent_id` (the creator of the record) and `dst_agent_id` (the receiver of the record). Tables in the device's database have no accessible auto-generated fields.

> We use the term “storage containers” for databases maintained on edge devices to differentiate them from the server-side databases. The eXtremeDB Active Replication Fabric APIs allow device-based applications to collect data, then transmit the collected data to servers when connected; likewise they allow communicating server-side data to IoT devices, usually for new device configuration and provisioning. This data flow is fully application-controlled through the Active Replication Framework push / pull interfaces. The APIs provide automatic or on-demand data exchange between collection points and servers.

> ## Database Schema IoT Definition

> Two schema definition declarations are required for Active Replication Framework (IoT) applications.

> ### IoT Declarations

> The declaration `iot server | router | device` is used in the database schema definition to declare that the database is intended to be used in the Active Replication Framework (IoT) applications. For example:

>         iot server;

> A router declaration must specify the `level` between 2 and 65534, and optionally an `agentId`. For example:

>         iot router<100> 15;

> or

>         iot router<100>;

> And an edge device has `level` 65534 and can optionally specify the `agentId. For example:`

>         iot device 1000;

> or

>         iot device;

> The declaration defines the role for the database: as a server or router database or a device storage container. Optionally, the `agentId` for the database can be specified. The `agentId` is a unique identifier for the database. If this `agentId` is not specified through the schema, it must be specified as a database parameter when opening the database.

> When `iot` is declared, the database runtime creates two hidden classes (tables) `@sys_iot_ts` and `@sys_iot_del`. The first table contains information about data sent or received from other iot nodes. The second table contains information about objects that were deleted from the container, which is necessary to propagate deletes to other iot nodes.

> ### Uptable and Downtable Class Modifiers

> The class modifiers `uptable` and `downtable` are used to define the replication direction. Classes defined as `uptable` are synchronized from the device to the server: any data modifications made to the devices’ storage container are propagated up to the server’s database. The `downtable` classes are synchronized downwards, i.e. from the server to the connected devices. Note that classes (tables) that are not designated as an `uptable` or a `downtable` are not replicated.

> An example of `uptable` classes could be sensor data collected in the devices’ storage container, which are replicated and then stored away in the server’s database. An example of a `downtable` class could be a device’s configuration parameters, or server-originated instructions, that are propagated to the device.

> All `uptable` and `downtable` classes include the automatically generated field `agent_id`; generated by the schema compiler. For the `uptable` classes, the `agent_id` identifies the device from which the object (record) was received. The server’s `downtable` tables’ the `agent_id` identifies the device nodes storage containers that the object (record) must be sent to. For example, the following class might be defined for the server database:

>         uptable class TempSensor
>         {
>             datetime          ts;
>             unsigned<4>   sensorId;
>             double             value;

>             tree<ts, agent_id, sensorId> ats;
>         };

> The `agent_id` field is not defined explicitly in the schema, but it can be used in indexes. For the `downtable` classes the default `agent_id` value is `MCO_IOT_ALL_AGENTS` which means that, by default, the server’s data is replicated to all device storage containers. It is possible to specify explicitly the value for `agent_id` which causes the server’s data to be replicated only to the specified node.

> In addition to the `agent_id` field, the `uptable` and `downtable` classes are also generated with two hidden indexed fields that identify the object and the timestamp of its last modification. Both fields and their index are automatically updated by the database runtime during a transaction commit that has modified the object. However note that these internally managed fields (`iot_object_id@` and `iot_timestamp@`) are not accessible to applications. The `iot_object_id@` value is like an `autoid_oid` except that it is local to the class, so to create a global identity it is combined with the `agent_id` of the node that the object was created on. The `iot_timestamp@` value is the logical timestamp (not the wall time) of the last modification of the object. Every transaction increments this counter and stores the new value. This is necessary to enforce IoT synchronization policies which identify objects that need to be sent to the next IoT level during synchronization. Therefore, if a timestamp value is required by the application, it is necessary to define a field, like `ts` in the above schema, that can be accessed and included in indexes if desired.