From 725a9b5d8808b14f296421190b3cb9e0c1c5996e Mon Sep 17 00:00:00 2001 From: Jonathan Shook Date: Sat, 9 Dec 2023 17:17:06 -0600 Subject: [PATCH] doc updates --- .../nb/api/components/package-info.java | 87 ++++++++++++------- 1 file changed, 57 insertions(+), 30 deletions(-) diff --git a/nb-api/src/main/java/io/nosqlbench/nb/api/components/package-info.java b/nb-api/src/main/java/io/nosqlbench/nb/api/components/package-info.java index 49c7384d8..dfd693b6e 100644 --- a/nb-api/src/main/java/io/nosqlbench/nb/api/components/package-info.java +++ b/nb-api/src/main/java/io/nosqlbench/nb/api/components/package-info.java @@ -32,21 +32,24 @@ * *

Components Defined

*

There can be different layers or types of components, but there is only one component hierarchy in each - * NoSQLBench process. Basically the Session is a component. The Scenario is a component. Each activity within a - * scenario is a component. Whether something is meaningful as a component depends on whether the management facilities - * provided by the component API make using, interacting with, or understanding that element better for users. However - * there is a limit to how fine-grained the component hierarchy should be allowed to get. This is because maintaining - * the component structure at runtime incurs a cost, and most feature of the component types are related to assemblage - * of fixtures in the runtime which are configured and initialized before steady state processing begins. For example, - * it makes sense to wire an activity as component, but not an operation, since an operation is ephemeral and - * short-lived. Apart from these trade-offs, make a layer a component layer if it makes sense for the user and/or the - * developer, as consolidating the logic into the component layer is beneficial to both.

+ * NoSQLBench process. Basically the Session is a component. Each activity container within a session is a component. + * Each activity within a container is a component. Whether something is meaningful as a component depends on whether + * the management facilities provided by the component API make using, interacting with, or understanding that element + * better for users. However there is a limit to how fine-grained the component hierarchy should be allowed to get. + * This + * is because maintaining the component structure at runtime incurs a cost, and most features of the component types + * are + * related to assemblage of fixtures in the runtime which are configured and initialized before steady state processing + * begins. For example, it makes sense to wire an activity as component, but not an operation, since an operation is + * ephemeral and short lived. Apart from these trade-offs, make a layer a component layer if it makes sense for the + * user + * and/or the developer, as consolidating the logic into the component layer is beneficial to both.

* *

Adoption Strategy

*

Consolidating existing logic to use the component types will be an incremental process. The base contract type - * {@link io.nosqlbench.nb.api.components.NBComponent} establishes the contract for any conforming types. As contract facets - * are added to this type, common logic can be implemented on the base implementation types where possible, allowing - * for the elision of duplicitous code from prior functionality.

+ * {@link io.nosqlbench.nb.api.components.core.NBComponent} establishes the contract for any conforming types. As + * contract facets are added to this type, common logic can be implemented on the base implementation types where + * possible, allowing for the elision of duplicitous code from prior functionality.

*

*

*


@@ -56,13 +59,18 @@ * *

Components are structured hierarchically. All components exist within the scope of their parent, with the only * exception being the root component, which has no parent. Components always know their parent from construction time. - * After a component is constructed, it is informed of children components being added and removed via - * {@link io.nosqlbench.nb.api.components.NBComponent#attachChild} and {@link io.nosqlbench.nb.api.components.NBComponent#detachChild} + * After a component is constructed, it is informed of child components being added and removed via + * {@link io.nosqlbench.nb.api.components.core.NBComponent#attachChild} and + * {@link io.nosqlbench.nb.api.components.core.NBComponent#detachChild} * methods.

* - *

Component logic should interact with other components using the component interfaces and types. No contextual - * typing or casting should be allowed within the component layer methods. Components only understand components by - * design, and breaking this abstraction is counter-productive at best.

+ *

Component-specific logic should interact with other components using the component interfaces and types. No + * contextual typing or casting should be allowed within the component layer methods, except in the case that types + * outside of the component type system are leveraging component layers for features of other non-component types. In + * other words, Component APIs should be thought of as a layer of primitives which sit on top of low-level Java + * primitive, and below those types which use them. Component logic can't understand higher types without breaking the + * seal on a useful abstraction. Components only understand components by design, and breaking this abstraction is + * counter-productive at best.

* *

Utility classes which understand how to interact with components should be used where possible when the * capabilities they provide are well-themed and cohesive. A Corollary to this is that each interface added to the core @@ -76,21 +84,40 @@ *

Life-cycle Oriented Components

*

Life-cycle components represent executions of some user-managed scope, like session, scenarios, or activities. * These components model the nesting structure of threads of execution, or for activities, groups of threads. As such, - * any sub-components they have are generally there to augment or contextualize the execution of the life-cycle component. - * In this case, the life-cycle component controls the life-line of its sub-components. When the life-cycle component is - * ready to finish its own execution, it will directly inform all components attached to it that it is time for them - * to do final housekeeping, including any final buffering and sending, connection tear-down, etc. As components, the parent - * component may not know what the details of these housekeeping steps are directly. But components are always something else too, - * and in the type-specific implementations which are triggered by component methods, appropriate integrations can take place.

+ * any sub-components they have are generally there to augment or contextualize the execution of the life-cycle + * component.

+ *

Life-cycle components may control the life-line of its sub-components. In that case, when the life-cycle + * component + * is ready to finish its own execution, it should directly inform all components attached to it that it is time for + * them to do final housekeeping, including any final buffering and sending, connection tear-down, etc. As components, + * the parent + * component may not know what the details of these housekeeping steps are directly. But components are always + * something else too, and in the type-specific implementations which are triggered by component methods, appropriate + * integrations can take place indirectly through the component API or events.

+ *

In other life-cycle components, the parent component can be thought of as a passive container over child + * components which + * may exit on their own terms. In this case, the parent component should have appropriate eventing and state tracking + * so that + * its life-cycle is properly bounded around the sub components. In other words, it would be a bug if all the sub + * components + * had completed their work and the parent component sat idle in the component hierarchy without completing itself or + * alternately + * sending events to trigger some other life-cycle cleanup. How this is handled is not specific explicitly for all + * components. + * Still, it is a design error to have idle components in the hierarchy with no durable life-cycle cleanup + * mechanism.

* *

Service Oriented Components

- *

Service components are those which are created as an attachment to other components. They may or may not have additional asynchronous - * behavior with respect to their parent component, but they are always in service of the parent component. For example, metrics instruments - * like counters are passive, but reporters which send these metrics outside of the system are active and on a schedule. - * Service-oriented components generally do not control the duration of their lifetimes. When they are working properly, they exist - * along-side and attached to their parent component for the full lifetime of that parent, and then are reaped on demand by the parent - * component.

- * + *

Service components are those which are created as an attachment to other components. They may or may not have + * additional asynchronous behavior with respect to their parent component, but they are always in service of the parent + * component. For example, metrics instruments like counters are passive, but reporters which send these metrics outside + * of the system are active and on a schedule. Service-oriented components generally do not control the duration of + * their lifetimes. When they are working properly, they exist along-side and attached to their parent component for the + * full lifetime of that parent, and then are reaped on demand by the parent component.

+ *

Ideally reaping of sub-components like this occurs naturally because of standard GC reachability rules. For this to + * work reliably, it is important that you attach components and their children correctly with the component tree, and + * avoid creating extraneous references across unrelated components or across component layers.

+ *

*


*

Labeling Consistency and interlocks

* TODO: labeling consistency