You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by dm...@apache.org on 2020/10/01 23:43:27 UTC
[ignite] branch IGNITE-7595 updated: ported C++ specific classes
This is an automated email from the ASF dual-hosted git repository.
dmagda pushed a commit to branch IGNITE-7595
in repository https://gitbox.apache.org/repos/asf/ignite.git
The following commit(s) were added to refs/heads/IGNITE-7595 by this push:
new fd5725f ported C++ specific classes
fd5725f is described below
commit fd5725f9f193521b59629184f4187c842e55e5ee
Author: Denis Magda <dm...@gridgain.com>
AuthorDate: Thu Oct 1 16:39:58 2020 -0700
ported C++ specific classes
---
docs/_data/toc.yaml | 28 ++-
docs/_docs/cpp-specific/cpp-objects-lifetime.adoc | 78 +++++++
.../cpp-platform-interoperability.adoc | 236 +++++++++++++++++++
docs/_docs/cpp-specific/cpp-serialization.adoc | 253 +++++++++++++++++++++
...options.adoc => net-configuration-options.adoc} | 0
...upport.adoc => net-cross-platform-support.adoc} | 0
...nt-options.adoc => net-deployment-options.adoc} | 0
...-cache.adoc => net-entity-framework-cache.adoc} | 0
...ution.adoc => net-java-services-execution.adoc} | 0
.../net-specific/{linq.adoc => net-linq.adoc} | 0
...ity.adoc => net-platform-interoperability.adoc} | 2 +-
...ading.adoc => net-remote-assembly-loading.adoc} | 0
...dalone-nodes.adoc => net-standalone-nodes.adoc} | 0
13 files changed, 586 insertions(+), 11 deletions(-)
diff --git a/docs/_data/toc.yaml b/docs/_data/toc.yaml
index 6bd41f0..4e7e349 100644
--- a/docs/_data/toc.yaml
+++ b/docs/_data/toc.yaml
@@ -431,30 +431,30 @@
url: extensions-and-integrations/cassandra/usage-examples
- title: DDL Generator
url: extensions-and-integrations/cassandra/ddl-generator
-- title: C# and .NET Specific
+- title: .NET Specific
items:
- title: Configuration Options
- url: net-specific/configuration-options
+ url: net-specific/net-configuration-options
- title: Deployment Options
- url: net-specific/deployment-options
+ url: net-specific/net-deployment-options
- title: Standalone Nodes
- url: net-specific/standalone-nodes
+ url: net-specific/net-standalone-nodes
- title: Logging
url: net-specific/net-logging
- title: LINQ
- url: net-specific/linq
+ url: net-specific/net-linq
- title: Java Services Execution
- url: net-specific/java-services-execution
+ url: net-specific/net-java-services-execution
- title: Plugins
url: net-specific/net-plugins
- title: Serialization
url: net-specific/net-serialization
- title: Cross-Platform Support
- url: net-specific/cross-platform-support
+ url: net-specific/net-cross-platform-support
- title: Platform Interoperability
- url: net-specific/platform-interoperability
+ url: net-specific/net-platform-interoperability
- title: Remote Assembly Loading
- url: net-specific/remote-assembly-loading
+ url: net-specific/net-remote-assembly-loading
- title: Troubleshooting
url: net-specific/net-troubleshooting
- title: Integrations
@@ -464,7 +464,15 @@
- title: ASP.NET Session State Caching
url: net-specific/asp-net-session-state-caching
- title: Entity Framework 2nd Level Cache
- url: net-specific/entity-framework-cache
+ url: net-specific/net-entity-framework-cache
+- title: C++ Specific
+ items:
+ - title: Serialization
+ url: cpp-specific/cpp-serialization
+ - title: Platform Interoperability
+ url: cpp-specific/cpp-platform-interoperability
+ - title: Objects Lifetime
+ url: cpp-specific/cpp-objects-lifetime
- title: Plugins
url: plugins
- title: SQL Reference
diff --git a/docs/_docs/cpp-specific/cpp-objects-lifetime.adoc b/docs/_docs/cpp-specific/cpp-objects-lifetime.adoc
new file mode 100644
index 0000000..b779cb2
--- /dev/null
+++ b/docs/_docs/cpp-specific/cpp-objects-lifetime.adoc
@@ -0,0 +1,78 @@
+= Objects Lifetime in Ignite.C++
+
+== Ignite Objects
+
+Apache Ignite objects, such as `Ignite` or `Cache`, that are created using Ignite public APIs are implemented as a thin
+handler of an internal/underlying object and can be safely and quickly copied or passed to functions by value. It is also
+a recommended way for passing Ignite objects from one function to another because an underlying object lives as long as
+there is at least one handler object alive.
+
+[tabs]
+--
+tab:C++[]
+[source,cpp]
+----
+// Fast and safe passing of the ignite::Ignite instance to the function.
+// Here 'val' points to the same underlying node instance even though
+// Ignite object gets copied on call.
+// It's guarateed that the underlying object will live as long as 'val'
+// object is alive.
+void Foo(ignite::Ignite val)
+{
+ ...
+}
+----
+--
+
+== Custom Objects
+Your application can put in Ignite custom objects which lifetime can not be easily
+determined during the compilation. For example, when a `ContinuousQuery` instance is created, you are required to
+provide the continuous query with an instance of the local listener - `CacheEntryEventListener`. In such a case, it is
+unclear whether it is the responsibility of Apache Ignite or the application to manage the local listener's lifetime and
+release it once it is no longer needed.
+
+Apache Ignite C{pp} is pretty flexible in this part. It uses `ignite::Reference` class to address custom objects ownership
+problem. Refer to the code below to see how this class can be used in practice.
+
+[tabs]
+--
+tab:C++[]
+[source,cpp]
+----
+// Ignite function that takes a value of 'SomeType'.
+void Foo(ignite::Reference<SomeType> val);
+
+//...
+
+// Defining an object.
+SomeType obj1;
+
+// Passing a simple reference to the function.
+// Ignite will not get ownership over the instance.
+// The application is responsible for keeping instance alive while
+// it's used by Ignite and for releasing it once it is no longer needed.
+Foo(ignite::MakeReference(obj1);
+
+// Passing the object by copy.
+// Ignite gets a copy of the object instance and manages
+// its lifetime by itself.
+// 'SomeType' is required to have a copy constructor.
+foo(ignite::MakeReferenceFromCopy(obj1);
+
+// Defining another object.
+SomeType* obj2 = new SomeType;
+
+// Passing object's ownership to the function.
+// Ignite will release the object once it's no longer needed.
+// The applicaiton must not use the pointer once it have been passed
+// to Ignite as it might be released at any point of time.
+foo(ignite::MakeReferenceFromOwningPointer(obj2);
+
+std::shared_ptr<SomeType> obj3 = std::make_shared<SomeType>();
+
+// Passing the object by smart pointer.
+// In this case, Reference class behaves just like an underlying
+// smart pointer type.
+foo(ignite::MakeReferenceFromSmartPointer(obj3);
+----
+--
diff --git a/docs/_docs/cpp-specific/cpp-platform-interoperability.adoc b/docs/_docs/cpp-specific/cpp-platform-interoperability.adoc
new file mode 100644
index 0000000..f24e070
--- /dev/null
+++ b/docs/_docs/cpp-specific/cpp-platform-interoperability.adoc
@@ -0,0 +1,236 @@
+= Ignite.C++ and Platform Interoperability
+
+== Overview
+
+When using Apache Ignite C++, it is quite common to have several C++ and Java nodes running in a single cluster. To seamlessly
+interoperate between C++ and Java nodes, you need to take several aspects into consideration. Let's review them.
+
+== Binary Marshaller Configuration
+
+Ignite uses its binary marshaller for data, logic, messages serialization and deserialization. Due to architectural specificities,
+Java and C++ nodes are started with different default settings of the binary marshaller that can lead to exceptions like
+ the one below during a node startup if you try to set up a heterogeneous cluster:
+
+[tabs]
+--
+tab:Java[]
+[source,java]
+----
+class org.apache.ignite.spi.IgniteSpiException: Local node's
+binary configuration is not equal to remote node's binary configuration
+[locNodeId=b3f0367d-3c2b-47b4-865f-a62c656b5d3f,
+rmtNodeId=556a3f41-eab1-4d9f-b67c-d94d77ddd89d,
+locBinaryCfg={globIdMapper=org.apache.ignite.binary.BinaryBasicIdMapper,
+compactFooter=false, globSerializer=null}, rmtBinaryCfg=null]
+----
+--
+
+To avoid the exception and to make sure Java and C++ nodes can co-exist in a single cluster, add the following binary
+marshaller's settings to the Java configuration:
+
+[tabs]
+--
+tab:XML[]
+[source,xml]
+----
+<?xml version="1.0" encoding="UTF-8"?>
+
+<beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.springframework.org/schema/beans
+ http://www.springframework.org/schema/beans/spring-beans.xsd">
+
+ <bean id="ignite.cfg" class="org.apache.ignite.configuration.IgniteConfiguration">
+ ...
+ <property name="binaryConfiguration">
+ <bean class="org.apache.ignite.configuration.BinaryConfiguration">
+ <property name="compactFooter" value="false"/>
+
+ <property name="idMapper">
+ <bean class="org.apache.ignite.binary.BinaryBasicIdMapper">
+ <property name="lowerCase" value="true"/>
+ </bean>
+ </property>
+ </bean>
+ </property>
+ ...
+ </bean>
+</beans>
+----
+--
+
+== Basic Types Compatibility
+
+Your C++ application can put a value into the cluster and another Java application can read it back. The table below
+shows how the types are matched between Java and C++:
+
+[opts="header"]
+|===
+|Java Type | C++ Type
+
+| `boolean`, `java.lang.Boolean`| `bool`
+| `byte`, `java.lang.Byte`| `int8_t`
+| `short`, `java.lang.Short`| `int16_t`
+| `int`, `java.lang.Integer`| `int32_t`
+| `long`, `java.lang.Long`| `int64_t`
+| `float`, `java.lang.Float`| `float`
+| `double`, `java.lang.Double`| `double`
+| `char`, `java.lang.Character`| `uint16_t`
+| `java.lang.String`| `std::string`, `char[]`
+| `java.util.Date`| `ignite::Date`
+| `java.sql.Time`| `ignite::Time`
+| `java.sql.Timestamp`| `ignite::Timestamp`
+| `java.util.UUID`| `ignite::Guid`
+|===
+
+== Custom Types Compatibility
+
+To get access to the same application-specific object on both Java and C++ nodes, you need to describe it similarly in
+both the languages. This includes the same type name, type id, fields id, hash code algorithm, as well as read/write functions
+for the type.
+
+To do this on the C++ end, you need to use the `ignite::binary::BinaryType` class template.
+
+Let's consider the following example that defines a Java class that will be later read by a C++ application:
+
+[tabs]
+--
+tab:Java[]
+[source,java]
+----
+package org.apache.ignite.examples;
+
+public class CrossClass implements Binarylizable {
+ private long id;
+
+ private int idPart;
+
+ public void readBinary(BinaryReader reader) throws BinaryObjectException {
+ id = reader.readLong("id");
+ idPart = reader.readInt("idPart");
+ }
+
+ public void writeBinary(BinaryWriter writer) throws BinaryObjectException {
+ writer.writeLong("id", id);
+ writer.writeInt("idPart", idPart);
+ }
+}
+----
+--
+
+Next, you create a counter-part on the C++ end:
+
+[tabs]
+--
+tab:C++[]
+[source,cpp]
+----
+namespace ignite
+{
+ namespace binary
+ {
+ template<>
+ struct BinaryType<CrossClass>
+ {
+ static int32_t GetTypeId()
+ {
+ return GetBinaryStringHashCode("CrossClass");
+ }
+
+ static void GetTypeName(std::string& name)
+ {
+ name = "CrossClass";
+ }
+
+ static int32_t GetFieldId(const char* name)
+ {
+ return GetBinaryStringHashCode(name);
+ }
+
+ static bool IsNull(const CrossClass& obj)
+ {
+ return false;
+ }
+
+ static void GetNull(CrossClass& dst)
+ {
+ dst = CrossClass();
+ }
+
+ static void Read(BinaryReader& reader, CrossClass& dst)
+ {
+ dst.id = reader.ReadInt64("id");
+ dst.idPart = reader.ReadInt32("idPart");
+ }
+
+ static void Write(BinaryWriter& writer, const CrossClass& obj)
+ {
+ writer.WriteInt64("id", obj.id);
+ writer.WriteInt32("idPart", obj.idPart);
+ }
+ };
+ }
+}
+----
+--
+
+Finally, you need to use the following `BinaryConfiguration` for **both** Java and C++ nodes:
+
+[tabs]
+--
+tab:XML[]
+[source,xml]
+----
+<?xml version="1.0" encoding="UTF-8"?>
+
+<beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.springframework.org/schema/beans
+ http://www.springframework.org/schema/beans/spring-beans.xsd">
+
+ <bean id="ignite.cfg" class="org.apache.ignite.configuration.IgniteConfiguration">
+ ...
+ <property name="binaryConfiguration">
+ <bean class="org.apache.ignite.configuration.BinaryConfiguration">
+ <property name="compactFooter" value="false"/>
+
+ <property name="idMapper">
+ <bean class="org.apache.ignite.binary.BinaryBasicIdMapper">
+ <property name="lowerCase" value="true"/>
+ </bean>
+ </property>
+
+ <property name="nameMapper">
+ <bean class="org.apache.ignite.binary.BinaryBasicNameMapper">
+ <property name="simpleName" value="true"/>
+ </bean>
+ </property>
+
+ <property name="classNames">
+ <list>
+ <value>org.apache.ignite.examples.CrossClass</value>
+ </list>
+ </property>
+ </bean>
+ </property>
+ ...
+ </bean>
+</beans>
+----
+--
+
+[CAUTION]
+====
+[discrete]
+It is especially important to implement `GetTypeName()` and `GetTypeId()` methods in the right manner for the types that
+are used for the keys.
+====
+
+[CAUTION]
+====
+[discrete]
+C++ function `GetBinaryStringHashCode()` always calculates hash as `BinaryBasicIdMapper` when its property `lowerCase` is set
+to `true`. So make sure you have the correct configuration for the `BinaryBasicIdMapper` if you are going to use this
+function to calculate the type id in C++.
+====
+
diff --git a/docs/_docs/cpp-specific/cpp-serialization.adoc b/docs/_docs/cpp-specific/cpp-serialization.adoc
new file mode 100644
index 0000000..8d7fe2a45
--- /dev/null
+++ b/docs/_docs/cpp-specific/cpp-serialization.adoc
@@ -0,0 +1,253 @@
+= Serialization in Ignite.C++
+
+
+== BinaryType Templates
+
+Most user-defined classes going through Ignite C{pp} API will be passed over the wire to other cluster nodes. These classes
+include your data records, compute tasks, and other objects.
+
+Passing objects of these classes over wire requires serialization. For Ignite C{pp} it can be achieved by providing
+a `BinaryType` class template for your object type:
+
+[tabs]
+--
+tab:C++[]
+[source,cpp]
+----
+class Address
+{
+ friend struct ignite::binary::BinaryType<Address>;
+public:
+ Address() { }
+
+ Address(const std::string& street, int32_t zip) :
+ street(street), zip(zip) { }
+
+ const std::string& GetStreet() const
+ {
+ return street;
+ }
+
+ int32_t GetZip() const
+ {
+ return zip;
+ }
+
+private:
+ std::string street;
+ int32_t zip;
+};
+
+template<>
+struct ignite::binary::BinaryType<Address>
+{
+ static int32_t GetTypeId()
+ {
+ return GetBinaryStringHashCode("Address");
+ }
+
+ static void GetTypeName(std::string& name)
+ {
+ name = "Address";
+ }
+
+ static int32_t GetFieldId(const char* name)
+ {
+ return GetBinaryStringHashCode(name);
+ }
+
+ static bool IsNull(const Address& obj)
+ {
+ return obj.GetZip() && !obj.GetStreet().empty();
+ }
+
+ static void GetNull(Address& dst)
+ {
+ dst = Address();
+ }
+
+ static void Write(BinaryWriter& writer, const Address& obj)
+ {
+ writer.WriteString("street", obj.GetStreet());
+ writer.WriteInt32("zip", obj.GetZip());
+ }
+
+ static void Read(BinaryReader& reader, Address& dst)
+ {
+ dst.street = reader.ReadString("street");
+ dst.zip = reader.ReadInt32("zip");
+ }
+};
+----
+--
+
+Also, you can use the raw serialization mode without storing names of the object's fields in the serialized form. This
+mode is more compact and performs faster, but disables SQL queries that require to keep the names of the fields in the serialized form:
+
+[tabs]
+--
+tab:C++[]
+[source,cpp]
+----
+template<>
+struct ignite::binary::BinaryType<Address>
+{
+ static int32_t GetTypeId()
+ {
+ return GetBinaryStringHashCode("Address");
+ }
+
+ static void GetTypeName(std::string& name)
+ {
+ name = "Address";
+ }
+
+ static int32_t GetFieldId(const char* name)
+ {
+ return GetBinaryStringHashCode(name);
+ }
+
+ static bool IsNull(const Address& obj)
+ {
+ return false;
+ }
+
+ static void GetNull(Address& dst)
+ {
+ dst = Address();
+ }
+
+ static void Write(BinaryWriter& writer, const Address& obj)
+ {
+ BinaryRawWriter rawWriter = writer.RawWriter();
+
+ rawWriter.WriteString(obj.GetStreet());
+ rawWriter.WriteInt32(obj.GetZip());
+ }
+
+ static void Read(BinaryReader& reader, Address& dst)
+ {
+ BinaryRawReader rawReader = reader.RawReader();
+
+ dst.street = rawReader.ReadString();
+ dst.zip = rawReader.ReadInt32();
+ }
+};
+----
+--
+
+== Serialization Macros
+
+Ignite C{pp} defines a set of utility macros that could be used to simplify the `BinaryType` specialization. Here is a list of such macros with description:
+
+* `IGNITE_BINARY_TYPE_START(T)` - Start the binary type's specialization.
+* `IGNITE_BINARY_TYPE_END` - End the binary type's specialization.
+* `IGNITE_BINARY_GET_TYPE_ID_AS_CONST(id)` - Implementation of `GetTypeId()` which returns predefined constant `id`.
+* `IGNITE_BINARY_GET_TYPE_ID_AS_HASH(T)` - Implementation of `GetTypeId()` which returns hash of passed type name.
+* `IGNITE_BINARY_GET_TYPE_NAME_AS_IS(T)` - Implementation of `GetTypeName()` which returns type name as is.
+* `IGNITE_BINARY_GET_FIELD_ID_AS_HASH` - Default implementation of `GetFieldId()` function which returns Java-way hash code of the string.
+* `IGNITE_BINARY_IS_NULL_FALSE(T)` - Implementation of `IsNull()` function which always returns `false`.
+* `IGNITE_BINARY_IS_NULL_IF_NULLPTR(T)` - Implementation of `IsNull()` function which return `true` if passed object is null pointer.
+* `IGNITE_BINARY_GET_NULL_DEFAULT_CTOR(T)` - Implementation of `GetNull()` function which returns an instance created with default constructor.
+* `IGNITE_BINARY_GET_NULL_NULLPTR(T)` - Implementation of GetNull() function which returns `NULL` pointer.
+
+You can describe the `Address` class declared earlier using these macros:
+
+[tabs]
+--
+tab:C++[]
+[source,cpp]
+----
+namespace ignite
+{
+ namespace binary
+ {
+ IGNITE_BINARY_TYPE_START(Address)
+ IGNITE_BINARY_GET_TYPE_ID_AS_HASH(Address)
+ IGNITE_BINARY_GET_TYPE_NAME_AS_IS(Address)
+ IGNITE_BINARY_GET_NULL_DEFAULT_CTOR(Address)
+ IGNITE_BINARY_GET_FIELD_ID_AS_HASH
+
+ static bool IsNull(const Address& obj)
+ {
+ return obj.GetZip() == 0 && !obj.GetStreet().empty();
+ }
+
+ static void Write(BinaryWriter& writer, const Address& obj)
+ {
+ writer.WriteString("street", obj.GetStreet());
+ writer.WriteInt32("zip", obj.GetZip());
+ }
+
+ static void Read(BinaryReader& reader, Address& dst)
+ {
+ dst.street = reader.ReadString("street");
+ dst.zip = reader.ReadInt32("zip");
+ }
+
+ IGNITE_BINARY_TYPE_END
+ }
+}
+----
+--
+
+== Reading and Writing Values
+
+There are several ways for writing and reading data. The first way is to use an object's value directly:
+
+
+[tabs]
+--
+tab:Writing[]
+[source,cpp]
+----
+CustomType val;
+
+// some application code here
+// ...
+
+writer.WriteObject<CustomType>("field_name", val);
+----
+tab:Reading[]
+[source,cpp]
+----
+CustomType val = reader.ReadObject<CustomType>("field_name");
+----
+--
+
+The second approach does the same but uses a pointer to the object:
+
+[tabs]
+--
+tab:Writing[]
+[source,cpp]
+----
+// Writing null to as a value for integer field.
+writer.WriteObject<int32_t*>("int_field_name", nullptr);
+
+// Writing a value of the custom type by pointer.
+CustomType *val;
+
+// some application code here
+// ...
+
+writer.WriteObject<CustomType*>("field_name", val);
+----
+tab:Reading[]
+[source,cpp]
+----
+// Reading value which can be null.
+CustomType* nullableVal = reader.ReadObject<CustomType*>("field_name");
+if (nullableVal) {
+ // ...
+}
+
+// You can use a smart pointer as well.
+std::unique_ptr<CustomType> nullablePtr = reader.ReadObject<CustomType*>();
+if (nullablePtr) {
+ // ...
+}
+----
+--
+
+An advantage of the pointer-based technique is that it allows writing or reading `null` values.
diff --git a/docs/_docs/net-specific/configuration-options.adoc b/docs/_docs/net-specific/net-configuration-options.adoc
similarity index 100%
rename from docs/_docs/net-specific/configuration-options.adoc
rename to docs/_docs/net-specific/net-configuration-options.adoc
diff --git a/docs/_docs/net-specific/cross-platform-support.adoc b/docs/_docs/net-specific/net-cross-platform-support.adoc
similarity index 100%
rename from docs/_docs/net-specific/cross-platform-support.adoc
rename to docs/_docs/net-specific/net-cross-platform-support.adoc
diff --git a/docs/_docs/net-specific/deployment-options.adoc b/docs/_docs/net-specific/net-deployment-options.adoc
similarity index 100%
rename from docs/_docs/net-specific/deployment-options.adoc
rename to docs/_docs/net-specific/net-deployment-options.adoc
diff --git a/docs/_docs/net-specific/entity-framework-cache.adoc b/docs/_docs/net-specific/net-entity-framework-cache.adoc
similarity index 100%
rename from docs/_docs/net-specific/entity-framework-cache.adoc
rename to docs/_docs/net-specific/net-entity-framework-cache.adoc
diff --git a/docs/_docs/net-specific/java-services-execution.adoc b/docs/_docs/net-specific/net-java-services-execution.adoc
similarity index 100%
rename from docs/_docs/net-specific/java-services-execution.adoc
rename to docs/_docs/net-specific/net-java-services-execution.adoc
diff --git a/docs/_docs/net-specific/linq.adoc b/docs/_docs/net-specific/net-linq.adoc
similarity index 100%
rename from docs/_docs/net-specific/linq.adoc
rename to docs/_docs/net-specific/net-linq.adoc
diff --git a/docs/_docs/net-specific/platform-interoperability.adoc b/docs/_docs/net-specific/net-platform-interoperability.adoc
similarity index 99%
rename from docs/_docs/net-specific/platform-interoperability.adoc
rename to docs/_docs/net-specific/net-platform-interoperability.adoc
index 3c2b4db..ac54a6d 100644
--- a/docs/_docs/net-specific/platform-interoperability.adoc
+++ b/docs/_docs/net-specific/net-platform-interoperability.adoc
@@ -1,4 +1,4 @@
-= Platform Interoperability
+= Ignite.NET and Platform Interoperability
Ignite allows different platforms, such as .NET, Java and C{pp}, to interoperate with each other.
Classes and objects defined and written to Ignite by one platform can be read and used by another platform.
diff --git a/docs/_docs/net-specific/remote-assembly-loading.adoc b/docs/_docs/net-specific/net-remote-assembly-loading.adoc
similarity index 100%
rename from docs/_docs/net-specific/remote-assembly-loading.adoc
rename to docs/_docs/net-specific/net-remote-assembly-loading.adoc
diff --git a/docs/_docs/net-specific/standalone-nodes.adoc b/docs/_docs/net-specific/net-standalone-nodes.adoc
similarity index 100%
rename from docs/_docs/net-specific/standalone-nodes.adoc
rename to docs/_docs/net-specific/net-standalone-nodes.adoc