mirror of
https://github.com/nosqlbench/nosqlbench.git
synced 2024-11-28 03:23:59 -06:00
docs update
This commit is contained in:
parent
da609d76da
commit
ac78ea5667
@ -2,13 +2,13 @@ package io.nosqlbench.adapter.prototype;
|
||||
|
||||
/*
|
||||
* Copyright (c) nosqlbench
|
||||
*
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
@ -21,6 +21,9 @@ package io.nosqlbench.adapter.prototype;
|
||||
import io.nosqlbench.adapters.api.activityimpl.uniform.BaseSpace;
|
||||
import io.nosqlbench.adapters.api.activityimpl.uniform.DriverAdapter;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public class ExampleSpace extends BaseSpace<ExampleSpace> {
|
||||
|
||||
public ExampleSpace(DriverAdapter<?, ExampleSpace> adapter, long idx) {
|
||||
|
@ -23,6 +23,9 @@ import io.nosqlbench.adapters.api.activityimpl.uniform.flowtypes.CycleOp;
|
||||
/**
|
||||
* This example of a space uses the <EM>SelfT</EM> technique to enable
|
||||
* the self type to be used in method signatures and return types.
|
||||
*
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @param <SelfT>
|
||||
*/
|
||||
public class BaseSpace<SelfT extends BaseSpace<SelfT> > implements Space {
|
||||
|
@ -35,120 +35,114 @@ import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.LongFunction;
|
||||
|
||||
/**
|
||||
* <P>The DriverAdapter interface is the top level API for implementing
|
||||
* operations in NoSQLBench. It defines the related APIs needed to fully realized an adapter
|
||||
* at runtime. A driver adapter can map op templates from YAML form to a fully executable
|
||||
* form in native Java code, just as an application might do with a native driver. It can also
|
||||
* do trivial operations, like simply calling {@code System.out.println(...)}. When you specify an adapter by name,
|
||||
* you are choosing both the available operations, and the rules for converting a YAML op template into those
|
||||
* operations. This is a two-step process: The adapter provides mapping logic for converting high-level templates from
|
||||
* users into op types, and separate dispensing logic which can efficiently create these ops at runtime. When used
|
||||
* together, they power <EM>op synthesis</EM> -- efficient and deterministic construction of runtime operations using
|
||||
* procedural generation methods.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* Generally speaking, a driver adapter is responsible for
|
||||
* <UL>
|
||||
* <LI>Defining a class type for holding related state known as a {@link Space}.
|
||||
* <UL><LI>The type of this is specified as
|
||||
* generic parameter {@link SPACETYPE}.</LI></UL></LI>
|
||||
* <LI>Defining a factory method for constructing an instance of the space.</LI>
|
||||
* <LI>Recognizing the op templates that are documented for it via an {@link OpMapper}
|
||||
* and assigning them to an op implementation.
|
||||
* <UL><LI>The base type of these ops is specified as generic
|
||||
* parameter {@link OPTYPE}.</LI></UL>
|
||||
* </LI>
|
||||
* <LI>Constructing dispensers for each matching op implementation with a matching {@link OpDispenser}</LI>
|
||||
* implementation.
|
||||
* </UL>
|
||||
* <P>At runtime, the chain of these together ({@code cycle -> op mapping -> op dispensing -> op}) is cached
|
||||
* as a look-up table of op dispensers. This results in the simpler logical form {@code cycle -> op synthesis ->
|
||||
* operation}.
|
||||
* </P>
|
||||
*
|
||||
* <H3>Variable Naming Conventions</H3>
|
||||
* <p>
|
||||
* Within the related {@link DriverAdapter} APIs, the following conventions are (more often) used, and will be found
|
||||
* everywhere:
|
||||
* <UL>
|
||||
* <LI>{@code namedF} describes a namedFunction variable. Functional patterns are used everywhere in these APIs
|
||||
* .</LI>
|
||||
* <LI>{@code namedC} describes a namedComponent variable. All key elements of the nosqlbench runtime are
|
||||
* part of a component tree.</LI>
|
||||
* <LI>{@code pop} describes a {@link ParsedOp} instance.</LI>
|
||||
* </UL>
|
||||
* </P>
|
||||
* <H3>Generic Parameters</H3>
|
||||
* <p>
|
||||
* When a new driver adapter is defined with the generic parameters below, it becomes easy to build out a matching
|
||||
* DriverAdapter with any modern IDE.</P>
|
||||
*
|
||||
* @param <OPTYPE>
|
||||
* The type of {@link CycleOp} which will be used to wrap all operations for this driver adapter. This allows you
|
||||
* to add context or features common to all operations of this type. This can be a simple <a
|
||||
* href="https://en.wikipedia.org/wiki/Marker_interface_pattern">Marker</a> interface, or it can be something more
|
||||
* concrete that captures common logic or state across all the operations used for a given adapter. It is highly
|
||||
* advised to <EM>NOT</EM> leave it as simply {@code CycleOp<?>}, since specific op implementations offer much
|
||||
* better performance.
|
||||
* @param <SPACETYPE>
|
||||
* The type of context space used by this driver to hold cached instances of clients, session, or other native
|
||||
* driver state. This is the shared state which might be needed during construction operations for an adapter.
|
||||
* <EM>No other mechanism is provided nor intended for holding adapter-specific state. You must store it in
|
||||
* this type. This includes client instances, codec mappings, or anything else that a single instance of an
|
||||
* application would need to effectively use a given native driver.</EM>
|
||||
*/
|
||||
|
||||
/// The DriverAdapter interface is the top level API for implementing
|
||||
/// operations in NoSQLBench. It defines the related APIs needed to fully realized an adapter
|
||||
/// at runtime. A driver adapter can map op templates from YAML form to a fully executable
|
||||
/// form in native Java code, and then execute those native operations just as an application might do directly with a
|
||||
/// native driver. It can also do trivial operations, like simply calling `System.out.println(...)`. What a
|
||||
/// particular DriverAdapter does is open-ended, but this usually means wrapping a native driver when supporting
|
||||
/// specific protocols.
|
||||
///
|
||||
/// Every DriverAdapter has a simple name, as indicated on it's [Service] annotation. When you
|
||||
/// specify an adapter by name, you are choosing both the available operations, and the rules for converting
|
||||
/// a YAML op template into those operations. This is a two-step process: Mapping user intentions, and generating
|
||||
/// executable operations, called op mapping and op dispensing, respectively. Each adapter provides implementations
|
||||
/// for both of these phases for all the op types is supports. When used together, they power _op synthesis_ --
|
||||
/// efficient and deterministic construction of runtime operations using procedural generation methods.
|
||||
///
|
||||
/// Generally speaking, a driver adapter is responsible for
|
||||
/// - Defining a class type for holding related state known as a [Space]. The type of this is specified as generic
|
||||
/// parameter [SPACETYPE]
|
||||
/// - Defining a factory method for constructing an instance of the space.
|
||||
/// - Recognizing the op templates that are documented for it via an [OpMapper] and assigning them to an op
|
||||
/// implementation. The base type of these ops is specified as generic [OPTYPE]
|
||||
/// - Constructing dispensers for each matching op implementation with a matching [OpDispenser] implementation.
|
||||
///
|
||||
/// At a high level, the following sequence is executed for every cycle in an activity:
|
||||
/// ```
|
||||
///[cycle value] -> op synthesis -> [executable op] -> op execution```
|
||||
///
|
||||
/// or in another way, simply `opExecution(opFunction(cycle))`.
|
||||
///
|
||||
/// This is a simplified view of the detailed steps, most of which are handled automatically by the nosqlbench engine:
|
||||
///
|
||||
/// ```
|
||||
/// cycle value
|
||||
/// -> op template sequencing # memoized
|
||||
/// -> op template selection # memoized
|
||||
/// -> op template parsing # memoized
|
||||
/// -> op template normalization # memoized
|
||||
/// -> op type mapping # memoized
|
||||
/// -> op dispensing
|
||||
/// -> op execution
|
||||
///```
|
||||
///
|
||||
/// Notice that all of the stages are optimized via a form of memoization. This is a side-effect of forcing the
|
||||
/// initialization of the op construction pipelines into lamda form, where unchanging initialization data is captured
|
||||
/// explicitly or by reference in closures. This works in our favor for performance, since these lambdas are
|
||||
/// optimized and executed very efficiently within modern Java VMs.
|
||||
///
|
||||
/// ### Variable Naming Conventions
|
||||
///
|
||||
/// Within the related [DriverAdapter] APIs, the following conventions are (more often) used, and will be
|
||||
/// found everywhere:
|
||||
/// - `namedF` describes a namedFunction variable. Functional patterns are used everywhere in these APIs.
|
||||
/// - `namedC` describes a namedComponent variable. All key elements of the nosqlbench runtime are part of a
|
||||
/// component tree.
|
||||
/// - `pop` describes a [ParsedOp] instance.
|
||||
///
|
||||
/// ### Generic Parameters
|
||||
/// When a new driver adapter is defined with the generic parameters below, it becomes easy to build out a matching
|
||||
/// [DriverAdapter] with any modern IDE.
|
||||
///
|
||||
/// @param OPTYPE The type of [CycleOp] which will be used to wrap all operations for this driver adapter. This
|
||||
/// allows you to add context or features common to all operations of this type. This can be a simple
|
||||
/// [marker](https://en.wikipedia.org/wiki/Marker_interface_pattern) interface, or it can be something more concrete
|
||||
/// that captures common logic or state across all the operations used for a given adapter. It is
|
||||
/// highly advised to _NOT_ leave it as simply `CycleOp<?>`, since specific op implementations offer much
|
||||
/// better performance.
|
||||
///
|
||||
/// @param SPACETYPE The type of context space used by this driver to hold cached instances of clients, session, or
|
||||
/// other native driver state. This is the shared state which might be needed during construction operations for an
|
||||
/// adapter. No other mechanism is provided nor intended for holding adapter-specific state. You must store it in
|
||||
/// this type. This includes client instances, codec mappings, or anything else that a single instance of an
|
||||
/// application would need to effectively use a given native driver.
|
||||
public interface DriverAdapter<OPTYPE extends CycleOp<?>, SPACETYPE extends Space> extends NBComponent {
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* <H2>Op Mapping</H2>
|
||||
* An Op Mapper is a function which can look at a {@link ParsedOp} and create a matching {@link OpDispenser}.
|
||||
* An OpDispenser is a function that will produce a special type {@link OPTYPE} that this DriverAdapter implements
|
||||
* as its op implementation. There may be many different ops supported by an adapter, thus there may be similarly
|
||||
* many dispensers.</p>
|
||||
*
|
||||
* <p>
|
||||
* Both {@link OpMapper} and {@link OpDispenser} are functions. The role of {@link OpMapper} is to
|
||||
* map the op template provided by the user to an op implementation provided by the driver adapter,
|
||||
* and then to create a factor function for it (the {@link OpDispenser}).</p>
|
||||
*
|
||||
* <p>These roles are split for a very good reason: Mapping what the user wants to do with an op template
|
||||
* is resource intenstive, and should be as pre-baked as possible. This phase is the <EM>op mapping</EM> phase.
|
||||
* It is essential that the mapping logic be very clear and maintainable. Performance is not as important
|
||||
* at this phase, because all of the mapping logic is run during initialization of an activity.
|
||||
* </p>
|
||||
* <p>
|
||||
* Conversely, <EM>op dispensing</EM> (the next phase) while an activity is running should be as efficient as
|
||||
* possible.
|
||||
* </p>
|
||||
*
|
||||
* @return a dispensing function for {@link OPTYPE} op generation
|
||||
*/
|
||||
///
|
||||
/// ## Op Mapping
|
||||
///
|
||||
/// An Op Mapper is a function which can look at a [ParsedOp] and create a matching [OpDispenser].
|
||||
/// An OpDispenser is a function that will produce a special type [OPTYPE] that this DriverAdapter implements.
|
||||
/// There may be many different ops supported by an adapter, thus there may be similarly many dispensers.
|
||||
///
|
||||
/// Both [OpMapper] and [OpDispenser] are functions. The role of [OpMapper] is to map the op template provided
|
||||
/// by the user to an op implementation provided by the driver adapter, and then to create a suitable function for
|
||||
/// creating that type of operations, known as the [OpDispenser].
|
||||
///
|
||||
/// These roles are split for a very good reason: Mapping what the user wants to do with an op template
|
||||
/// is resource intensive, and should be as pre-baked as possible. This phase is the _op mapping_ phase.
|
||||
/// It is essential that the mapping logic be very clear and maintainable. Performance is not as important
|
||||
/// at this phase, because all of the mapping logic is run during initialization of an activity.
|
||||
///
|
||||
/// Conversely, _op dispensing_ (the next phase) while an activity is running should be as efficient as possible.
|
||||
/// @return a dispensing function for an [OPTYPE] op generation
|
||||
OpMapper<OPTYPE, SPACETYPE> getOpMapper();
|
||||
|
||||
/**
|
||||
* The preprocessor function allows the driver adapter to remap
|
||||
* the fields in the op template before they are interpreted canonically.
|
||||
* At this level, the transform is applied once to the input map
|
||||
* (once per op template) to yield the map that is provided to
|
||||
* {@link OpMapper} implementations. <EM>This is here to make backwards compatibility
|
||||
* possible for op templates which have changed. Avoid using it unless necessary.</EM>
|
||||
*
|
||||
* @return A function to pre-process the op template fields.
|
||||
*/
|
||||
/// The preprocessor function allows the driver adapter to remap the fields in the op template before they are
|
||||
/// interpreted canonically. At this level, the transform is applied once to the input map (once per op
|
||||
/// template) to yield the map that is provided to [OpMapper] implementations. _This is here to make
|
||||
/// backwards compatibility possible for op templates which have changed. Avoid using it unless necessary._
|
||||
/// @return A function to pre-process the op template fields.
|
||||
default Function<Map<String, Object>, Map<String, Object>> getPreprocessor() {
|
||||
return f -> f;
|
||||
}
|
||||
|
||||
/**
|
||||
* When a driver needs to identify an error uniquely for the purposes of
|
||||
* routing it to the correct error handler, or naming it in logs, or naming
|
||||
* metrics, override this method in your activity.
|
||||
*
|
||||
* @return A function that can reliably and safely map an instance of Throwable to a stable adapter-specific name.
|
||||
*/
|
||||
|
||||
/// When a driver needs to identify an error uniquely for the purposes of routing it to the correct error
|
||||
/// handler, or naming it in logs, or naming metrics, override this method in your activity.
|
||||
/// @return A function that can reliably and safely map an instance of Throwable to a stable adapter-specific name.
|
||||
default Function<Throwable, String> getErrorNameMapper() {
|
||||
return t -> t.getClass().getSimpleName();
|
||||
}
|
||||
@ -157,20 +151,17 @@ public interface DriverAdapter<OPTYPE extends CycleOp<?>, SPACETYPE extends Spac
|
||||
return List.of(f -> f);
|
||||
}
|
||||
|
||||
/**
|
||||
* <P>This method allows each driver adapter to create named state which is automatically
|
||||
* cached and re-used by name. For each (driver,space) combination in an activity,
|
||||
* a distinct space instance will be created. In general, adapter developers will
|
||||
* use the space type associated with an adapter to wrap native driver instances
|
||||
* one-to-one. As such, if the space implementation is a {@link AutoCloseable},
|
||||
* it will be explicitly shutdown as part of the activity shutdown.</P>
|
||||
*
|
||||
* <p>It is not necessary to implement a space for a stateless driver adapter, or one
|
||||
* which puts all state into each op instance.</p>
|
||||
*
|
||||
* @return A function which can initialize a new Space, which is a place to hold
|
||||
* object state related to retained objects for the lifetime of a native driver.
|
||||
*/
|
||||
/// This method allows each driver adapter to create named state which is automatically cached and re-used by
|
||||
/// name. For each (driver,space) combination in an activity, a distinct space instance will be created. In
|
||||
/// general, adapter developers will use the space type associated with an adapter to wrap native driver
|
||||
/// instances one-to-one. As such, if the space implementation is an [AutoCloseable], it will be
|
||||
/// explicitly shutdown as part of the activity shutdown.
|
||||
///
|
||||
/// It is not necessary to implement a space for a stateless driver adapter, or one which injects all necessary
|
||||
/// state into each op instance.
|
||||
///
|
||||
/// @return A function which can initialize a new Space, which is a place to hold object state related to
|
||||
/// retained objects for the lifetime of a native driver.
|
||||
default LongFunction<SPACETYPE> getSpaceInitializer(NBConfiguration cfg) {
|
||||
return n -> (SPACETYPE) new Space() {
|
||||
@Override
|
||||
@ -180,38 +171,38 @@ public interface DriverAdapter<OPTYPE extends CycleOp<?>, SPACETYPE extends Spac
|
||||
};
|
||||
}
|
||||
|
||||
/// Provides the configuration for this driver adapter, which comes from the superset of
|
||||
/// activity parameters given for the owning activity. Presently, the driver adapter acts
|
||||
/// as a proxy to set these parameters on the space, but this will likely be updated.
|
||||
/// Instead, the configuratin will be properly attached to the space directly, and the APIs
|
||||
/// supporting it will enforce this.
|
||||
NBConfiguration getConfiguration();
|
||||
|
||||
/**
|
||||
* The standard way to provide docs for a driver adapter is to put them in one of two common places:
|
||||
* <ul>
|
||||
* <li><resources>/<adaptername>.md - A single markdown file which is the named top-level
|
||||
* markdown file for this driver adapter.</li>
|
||||
* <li><resources>/docs/<adaptername>/ - A directory containing any type of file which
|
||||
* is to be included in docs under the adapter name, otherwise known as the {@link Service#selector()}</li>
|
||||
* <li><resources>/docs/<adaptername>.md</li>
|
||||
* </ul>
|
||||
*
|
||||
* <P><EM>A build will fail if any driver adapter implementation is missing at least one self-named
|
||||
* markdown doc file.</EM></P>
|
||||
*
|
||||
* @return A {@link DocsBinder} which describes docs to include for a given adapter.
|
||||
*/
|
||||
/// The standard way to provide docs for a driver adapter is to put them in one of two common places:
|
||||
/// - `resources/<adaptername>.md`
|
||||
/// - A single markdown file which is the named top-level markdown file for this driver adapter.
|
||||
/// - `resources/docs/<adaptername>/`
|
||||
/// - A directory containing any type of file which is to be included in docs under the adapter name, otherwise
|
||||
/// known as the [Service#selector()]
|
||||
/// - `resources/docs/<adaptername>.md`
|
||||
/// - An alternate location for the main doc file for an adapter, assuming you are using the docs/ path.
|
||||
///
|
||||
/// _A build will fail if any driver adapter implementation is missing at least one self-named markdown doc file._
|
||||
///
|
||||
/// @return A [DocsBinder] which describes docs to include for a given adapter.
|
||||
default DocsBinder getBundledDocs() {
|
||||
Docs docs = new Docs().namespace("drivers");
|
||||
|
||||
String dev_docspath = "adapter-" + this.getAdapterName() + "/src/main/resources/docs/" + this.getAdapterName();
|
||||
String cp_docspath = "docs/" + this.getAdapterName();
|
||||
Optional<Content<?>> bundled_docs = NBIO.local().pathname(dev_docspath, cp_docspath).first();
|
||||
bundled_docs.map(Content::asPath).ifPresent(docs::addContentsOf);
|
||||
|
||||
Optional<Content<?>> maindoc = NBIO.local().pathname("/src/main/resources/" + this.getAdapterName() + ".md", this.getAdapterName() + ".md").first();
|
||||
|
||||
maindoc.map(Content::asPath).ifPresent(docs::addPath);
|
||||
|
||||
return docs.asDocsBinder();
|
||||
}
|
||||
|
||||
/// Provide the simple name for this [DriverAdapter] implementation, derived from the
|
||||
/// required [Service] annotation.
|
||||
default String getAdapterName() {
|
||||
Service svc = this.getClass().getAnnotation(Service.class);
|
||||
if (svc == null) {
|
||||
@ -220,31 +211,41 @@ public interface DriverAdapter<OPTYPE extends CycleOp<?>, SPACETYPE extends Spac
|
||||
return svc.selector();
|
||||
}
|
||||
|
||||
/// Indicate the level of testing and muturity for the current adapter. This is not actively used
|
||||
/// and may be removed.
|
||||
/// @deprecated
|
||||
default Maturity getAdapterMaturity() {
|
||||
return this.getClass().getAnnotation(Service.class).maturity();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>The cache of all objects needed within a single instance
|
||||
* of a DriverAdapter which are not operations. These are generally
|
||||
* things needed by operations, or things needed during the
|
||||
* construction of operations.</p>
|
||||
*
|
||||
* <p>During Adapter Initialization, Op Mapping, Op Synthesis, or Op Execution,
|
||||
* you may need access to the objects in (the or a) space cache. You can build the
|
||||
* type of context needed and then provide this function to provide new instances
|
||||
* when needed.</p>
|
||||
*
|
||||
* <p>The function returned by this method is specialized to the space mapping
|
||||
* logic in the op template. Specifically, it uses whatever binding is set on a given
|
||||
* op template for the <em>space</em> op field. If none are provided, then this
|
||||
* becomes a short-circuit for the default '0'. If a non-numeric binding is provided,
|
||||
* then an interstitial mapping is added which converts the {@link Object#toString()}
|
||||
* value to ordinals using a hash map. This is less optimal by far than using
|
||||
* any binding that produces a {@link Number}.</p>
|
||||
*
|
||||
* @return A cache of named objects
|
||||
*/
|
||||
/// The function returned by [#getSpaceFunc(ParsedOp)] provides access to a cache of all stateful objects needed
|
||||
/// within a single instance of a DriverAdapter. These are generally things needed by operations, or things
|
||||
/// needed during the construction of operations. Typically, a space is where you store a native driver instance
|
||||
/// which is expected to be created/initialized once and reused within an application. Generally, users can
|
||||
/// think of __space__ as __driver instance__, or __client instance__, although there are driver adapters that
|
||||
/// do things other than wrap native drivers and clients.
|
||||
///
|
||||
/// The value of the op field `space` is used to customize the instancing behavior of spaces. If none is provided
|
||||
/// by the user, then only a singular space will be created for a given adapter in an activity. This is normal,
|
||||
/// and what most users will expect to do. However, customizing the space selector can be a powerful way to test
|
||||
/// any system with high logical concurrency. For example, each instance of a native driver will typically
|
||||
/// maintain its own thread or connection pools, cached resources and so on. ( Unless the developers of
|
||||
/// said native driver are breaking encapsulation by using global singletons in the runtime, which is highly
|
||||
/// frowned upon.) The spaces feature allows any nosqlbench workload to be easily converted into an unreasonably parallel
|
||||
/// client topology test with a single change. It works the same way for any adapter or protocol supported by
|
||||
/// nosqlbench.
|
||||
///
|
||||
/// The value of the op field `space` should be a [Number] type. [Number#intValue()] is used to determine which
|
||||
/// space instance is, if needed, initialized first, and then returned. If users provide a non-[Number] type,
|
||||
/// then an enumerating layer is added inline to convert any such value to an integer, which is less optimal.
|
||||
///
|
||||
/// During op mapping or dispensing, you may need access to state held by a driver-specific implementation of
|
||||
/// [SPACETYPE]. In the initialization phase, you only have access to the space function itself.
|
||||
/// This is important to maintain a boundary betwen the explicitly stateless and stateful parts of the
|
||||
/// runtime. To use the space, incorporate the space function into the lambdas which produce the operation to be
|
||||
/// executed. This is typically done in the construtor of the related [OpDispenser].
|
||||
///
|
||||
/// @return A cache of named objects
|
||||
public LongFunction<SPACETYPE> getSpaceFunc(ParsedOp pop);
|
||||
|
||||
}
|
||||
|
@ -26,8 +26,9 @@ import io.nosqlbench.nb.api.components.core.NBNamedElement;
|
||||
* in testing scenarios. Within the operations for an adapter, the space
|
||||
* may be needed, for example, to construct prepared statements, or other
|
||||
* 'session-attached' objects. Put any state that you would normally
|
||||
* associate with an instance of a native driver into a space, and use
|
||||
* the {@link DriverAdapter#getSpaceCache()} to access it when needed.</P>
|
||||
* associate with an instance of a native driver into a space.
|
||||
* A function to access the cycle-specific space instance is provided where
|
||||
* you might needed, such as in the mapping or dispensing APIs.
|
||||
*/
|
||||
public interface Space extends NBNamedElement, AutoCloseable {
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user