.. _arch_overview_data_sharing_between_filters: Sharing data between filters ============================ Envoy provides the following mechanisms for the transfer of configuration, metadata and per-request/connection state to, from and between filters, as well as to other core subsystems (e.g., access logging). Static State ^^^^^^^^^^^^ Static state is any immutable state specified at configuration load time (e.g., through xDS). There are three categories of static state: Metadata -------- Several parts of Envoy configuration (e.g. listeners, routes, clusters) contain a :ref:`metadata ` where arbitrary key-value pairs can be encoded. The typical pattern is to use the filter names in reverse DNS format as the key and encode filter specific configuration metadata in the value. This metadata is immutable and shared across all requests/connections. Such config metadata is usually provided during bootstrap time or as part of xDS. For example, weighted clusters in HTTP routes use the metadata to indicate the labels on the endpoints corresponding to the weighted cluster. Another example, the subset load balancer uses the metadata from the route entry corresponding to the weighted cluster to select appropriate endpoints in a cluster Typed Metadata -------------- :ref:`Metadata ` as such is untyped. Before acting on the metadata, callers typically convert it to a typed class object. The cost of conversion becomes non-negligible when performed repeatedly (e.g., for each request stream or connection). Typed Metadata solves this problem by allowing filters to register a one time conversion logic for a specific key. Incoming config metadata (via xDS) is converted to class objects at config load time. Filters can then obtain a typed variant of the metadata at runtime (per request or connection), thereby eliminating the need for filters to repeatedly convert from ``ProtobufWkt::Struct`` to some internal object during request/connection processing. For example, a filter that desires to have a convenience wrapper class over an opaque metadata with key ``xxx.service.policy`` in ``ClusterInfo`` could register a factory ``ServicePolicyFactory`` that inherits from ``ClusterTypedMetadataFactory``. The factory translates the ``ProtobufWkt::Struct`` into an instance of ``ServicePolicy`` class (inherited from ``FilterState::Object``). When a ``Cluster`` is created, the associated ``ServicePolicy`` instance will be created and cached. Note that typed metadata is not a new source of metadata. It is obtained from metadata that is specified as part of the configuration. A ``FilterState::Object`` implements ``serializeAsProto`` method can be configured in access loggers to log it. HTTP Per-Route Filter Configuration ----------------------------------- In HTTP routes, :ref:`typed_per_filter_config ` allows HTTP filters to have virtualhost/route-specific configuration in addition to a global filter config common to all virtual hosts. This configuration is converted and embedded into the route table. It is up to the HTTP filter implementation to treat the route-specific filter config as a replacement to global config or an enhancement. For example, the HTTP fault filter uses this technique to provide per-route fault configuration. ``typed_per_filter_config`` is a ``map``. The Connection manager iterates over this map and invokes the filter factory interface ``createRouteSpecificFilterConfigTyped`` to parse/validate the struct value and convert it into a typed class object that’s stored with the route itself. HTTP filters can then query the route-specific filter config during request processing. Dynamic State ^^^^^^^^^^^^^ Dynamic state is generated per network connection or per HTTP stream. Dynamic state can be mutable if desired by the filter generating the state. ``Envoy::Network::Connection`` and ``Envoy::Http::Filter`` provide a ``StreamInfo`` object that contains information about the current TCP connection and HTTP stream (i.e., HTTP request/response pair) respectively. ``StreamInfo`` contains a set of fixed attributes as part of the class definition (e.g., HTTP protocol, requested server name, etc.). In addition, it provides a facility to store typed objects in a map (``map``). The state stored per filter can be either write-once (immutable), or write-many (mutable). See :ref:`the well-known dynamic metadata ` and :ref:`the well-known filter state ` for the reference list of the dynamic metadata and the filter state objects. .. _arch_overview_advanced_filter_state_sharing: Filter state sharing -------------------- Filter state objects are bound to the lifespan of the associated parent stream. However, by marking a downstream object as shared with the upstream connection during creation, the object is shared with the upstream connection filter state, and its lifespan is extended beyond the original stream. Any upstream TCP or HTTP filter can access the shared object. Upstream transport sockets can also read the shared objects and customize the creation of the upstream transport. For example, the :ref:`internal upstream transport socket ` copies references to the shared objects to the internal connection downstream filter state. The filter state objects that are shared with the upstream also affect the connection pooling decisions if they implement a hashing interface. Whenever a shared hashable object is added, an upstream connection is created for each distinct hash value, which ensures that these objects are not overwritten by subsequent downstream requests to the same upstream connection. For example, a custom HTTP filter may create a shared hashable object from the value of a special header. In this case, a separate upstream connection is created for each distinct special header value, so that no two requests with different header values share an upstream connection. The same procedure applies to each shared hashable object individually, creating a combination matrix of the upstream connections per distinct combination of the object values.