The Environment in the Probes Open API

How Satoris shares/records data and configure extension points.

The Environment interface in the Probes Open API has a number of uses within the Satoris implementation of the underlying metering engine.

  • Thread Context Values
  • Global Environment Variables
  • Extension Point Configuration
  • Recorded Event Data
http://www.autoletics.com/probes-api/org/jinspired/probes/Probes.Environment.html

Thread Context Values

The Environment interface, accessible via the thread specific Context interface, allows for reading and writing of immutable data values such as String, long, int, boolean, double, and Name.

Note: The data type for named values is limited to allow memory offloading.

Values are local to the current thread and so can be accessed and updated from different call stack frames and across requests on the same thread.

Note: By default, there is no scoping of values to a particular probe call frame.
https://gist.github.com/autoletics/941cae1fdcbd1f62a3d8c5b19d83ea65

The Environment acts much like a Map with entries keyed on a Name. But unlike a Map, the Environment is hierarchical namespace aware offering a way to query the presence of values as well as removal using a Name prefix.

In the code snippet above user is the Name prefix of user.id.

Here’s the console output of the code executed within a metered runtime.

https://gist.github.com/autoletics/df1a8dfa44510611ec33374fabbff02f

The Environment interface can also be used to access read-only metadata associated with the current thread. This information is similar to what is offered by the Thread class. This might appear redundant, until factoring in the interesting novel capabilities offered by add-ons such as Stenos and Simz allowing the exact same code to be executed within a lightweight simulated environment replaying episodic memories of one or more Java runtimes.

https://gist.github.com/autoletics/af60c6ca59802ea73183c578fe723136
The Environment interface allows extension point code, such as interceptors or strategies, to be independent of the execution process — real or simulated.
https://gist.github.com/autoletics/0a393494d691696c29bc9d309fce7fab

In the Satoris implementation there exist multiple Environment instances chained together with only the leaf instance accessible via the Context.

The Environment returned from the Context.getEnvironment method is mutable. So named values can be added, updated and removed locally. But when querying a value mapped to a Name resolution starts with the target instance and when not found is delegated upwards to a parent instance.

The Thread metadata, created by the metering engine, cannot be removed or changed. The values are read-only, though it is possible to hide a value using the mutable Environment and setting a new value including null.

https://gist.github.com/autoletics/adc0ffb87df4c415624c300d5877b4a8

The Environment interface is also used to pass data back-and-forth between the application and metering extensions enabled within the runtime.

An example of this would be the current metering extension in Satoris which allows an application to determine the name of the active probe.

https://gist.github.com/autoletics/7fa427c35dfa0696900f450b8d342bd2
https://gist.github.com/autoletics/5ed858f179ed040bba88ca718c24580f

The qos metering extension in Sentris, which builds on top of the Satoris foundation, allows for an application to dynamically override the priority level for the current QoS Service associated with the running thread.

https://gist.github.com/autoletics/6906856d1d2e9423ac51513cd19851ae
The Environment interface reduces the overall surface area of the Open API in not polluting the Context with many [get|set]${SpecificThing}() methods — especially important when a metering engine has many optional extensions.

Global Environment Variables

Satoris also uses the Environment interface to expose metadata associated with the process. Similar to extensions the Environment data is read-only.

read access delegation

To the application the global metadata variables appear to be contained within the local Environment accessible from the thread Context. In fact any Environment used in the Open API delegates to this global instance.

Again using the Environment to access process information ensures that the code can be run within both a real or simulated software machine process.

https://gist.github.com/autoletics/c3a7ce1dcca9ec4058973ea3169a17f2
Note: In Simz there’s no one process Environment instance as a runtime can be simultaneously playing back episodic memories for multiple metered processes.
https://gist.github.com/autoletics/3ced1569c1d0106eafc4f298f1750a66

Satoris allows for the setting of global variables beyond what the metering engine already captures and sets. Here is a configuration file specifying some global variables. The last two variables are mapped to existing system variables — a Java system property and a system-dependent named variable.

Note: The Satoris configuration allows for the type specification of variables.
https://gist.github.com/autoletics/f1c42d7ece44867f30d2e49c30ca5426
Note: The same property spec pattern is used in configuring extension points.

And the code to access the above custom global variables from any thread.

https://gist.github.com/autoletics/5980322610e52b33f70fe95ab08c1e00
https://gist.github.com/autoletics/c7c1bab02f7ca2a7bd4db5867e96aed4

Extension Point Configuration

The Environment interface is also used to pass configuration to extension points in Satoris. Below an interceptor is passed the name of it’s meter.

https://gist.github.com/autoletics/268a53a4959434ea5465237c19edffcd

The InterfaceFactory class is passed an Environment via the init method.

https://gist.github.com/autoletics/20b3f85fa29f2f6cd1a6e02723f2337a

The measure and strategy extension points offer the same init method.

Note: Global environment variables are also resolvable from the Environment. This is useful where multiple extension points share a common configuration.

Recorded Event Data

Both the stenos and simz metering extensions intercept Environment calls and write the set data values within their respective metering event streams along with other metering events and metadata. When the ultra-compressed binary event stream is played back at some later point inside a simulation the values are made present at probe call boundaries — begin() and end().

https://gist.github.com/autoletics/11bc7eb861e00cd101b2b3f3026ef48e

One way to see it is that before the instrumented move() call is made the X and Y parameters are pushed on/into the corresponding probe stack frame.

To see the above code in action check out the following walkthrough video.

Collective Intelligence - Distributed Replication & Simulated Playback

A visual demonstration of how to augment the collective execution behavior of multiple software applications within a single simulated process. April 2014

https://vimeo.com/91285308

Additional API Design Notes

Iteration

The Environment interface doesn’t allow for the iteration over named values. The thinking being that values should only be accessible, to both application and extensions, on a need to know basis. If the name is not known, made public docs, then the value can’t be retrieved. Not offering iteration allows for performance optimizations and reduces design and development work when employing chained name resolution and memory management.

Defaults

A common use case for Environment is to override defaults. To make such coding easier there’s a get${Type}(Name,${Type}) method for each type.

Scoping

While the Environment is accessible via the thread Context it does not altogether preclude the underlying metering engine implementation from creating frames, scopes, restricting the lifecycle of the values to that of the active probe metering window — between the begin() and end() calls. This is in contrast to the OpenTracing API which practically forces implementors to incur large and unnecessary temporary heap object allocations per trace.

Values can still be scoped by the application itself using a try-finally code block though this would not be applicable to re-entrant methods.

https://gist.github.com/autoletics/c3a83909febec391b5148ff85b4d34b4
Satoris 2.8 will offer an optional metering extension that automatically stacks.

Nulls

The Environment interface makes a distinction between not present and null. The contains(Name) method reports on the existence of a Name within the map whereas isNull(Name) on the value of the named value. This is required when values, passed as parameters, can be primitive types.

Structures

Other than Name and String all data values are primitive types. More complex data structures can be supported by setting multiple values with a common namespace.

https://gist.github.com/autoletics/f85087e7af308ad97e534ce6e384ce23