diff --git a/src/UserGuide/Master/Tree/API/Programming-CSharp-Native-API.md b/src/UserGuide/Master/Tree/API/Programming-CSharp-Native-API.md index 2a85b3c32..eab64cbab 100644 --- a/src/UserGuide/Master/Tree/API/Programming-CSharp-Native-API.md +++ b/src/UserGuide/Master/Tree/API/Programming-CSharp-Native-API.md @@ -1,213 +1,170 @@ # C# Native API -## 1. Installation +## 1. Environment Requirements -### 1.1 Install from NuGet Package +* .NET SDK >= 5.0 or .NET Framework 4.x +* Thrift >= 0.14.1 +* NLog >= 4.7.9 -We have prepared Nuget Package for C# users. Users can directly install the client through .NET CLI. [The link of our NuGet Package is here](https://www.nuget.org/packages/Apache.IoTDB/). Run the following command in the command line to complete installation - -```sh -dotnet add package Apache.IoTDB -``` +## 2. Dependency Installation -Note that the `Apache.IoTDB` package only supports versions greater than `.net framework 4.6.1`. +You can use NuGet Package Manager, .NET CLI, or other tools to install the required packages. -## 2. Prerequisites +Using .NET CLI: - .NET SDK Version >= 5.0 - .NET Framework >= 4.6.1 +If you are using .NET 5.0 or later, run the following command to install the latest NuGet package -## 3. How to Use the Client (Quick Start) +```Bash +dotnet add package Apache.IoTDB +``` -Users can quickly get started by referring to the use cases under the Apache-IoTDB-Client-CSharp-UserCase directory. These use cases serve as a useful resource for getting familiar with the client's functionality and capabilities. +For .NET Framework 4.x, we provide a separate NuGet package. Run -For those who wish to delve deeper into the client's usage and explore more advanced features, the samples directory contains additional code samples. +```Bash +dotnet add package Apache.IoTDB.framework +``` -## 4. Developer environment requirements for iotdb-client-csharp +To install an older version, specify the version explicitly -``` -.NET SDK Version >= 5.0 -.NET Framework >= 4.6.1 -ApacheThrift >= 0.14.1 -NLog >= 4.7.9 +```Bash +# Install v0.12.1.2 +dotnet add package Apache.IoTDB --version 0.12.1.2 ``` -### 4.1 OS +## 3. Quick Start -* Linux, Macos or other unix-like OS -* Windows+bash(WSL, cygwin, Git Bash) +```C# +// Define parameters +string host = "localhost"; +int port = 6667; +int pool_size = 2; -### 4.2 Command Line Tools +// Initialize session pool +var session_pool = new SessionPool(host, port, pool_size); -* dotnet CLI -* Thrift +// Open session +await session_pool.Open(false); -## 5. Basic interface description +// Create time series +await session_pool.CreateTimeSeries("root.test_group.test_device.ts1", TSDataType.TEXT, TSEncoding.PLAIN, Compressor.UNCOMPRESSED); +await session_pool.CreateTimeSeries("root.test_group.test_device.ts2", TSDataType.BOOLEAN, TSEncoding.PLAIN, Compressor.UNCOMPRESSED); +await session_pool.CreateTimeSeries("root.test_group.test_device.ts3", TSDataType.INT32, TSEncoding.PLAIN, Compressor.UNCOMPRESSED); -The Session interface is semantically identical to other language clients +// Insert a record +var measures = new List{"ts1", "ts2", "ts3"}; +var values = new List { "test_text", true, (int)123 }; +var timestamp = 1; +var rowRecord = new RowRecord(timestamp, values, measures); +await session_pool.InsertRecordAsync("root.test_group.test_device", rowRecord); -```csharp -// Parameters -string host = "localhost"; -int port = 6667; -int pool_size = 2; +// Insert a tablet +var timestamp_lst = new List{ timestamp + 1 }; +var value_lst = new List {"iotdb", true, (int) 12}; +var tablet = new Tablet("root.test_group.test_device", measures, value_lst, timestamp_lst); +await session_pool.InsertTabletAsync(tablet); -// Init Session -var session_pool = new SessionPool(host, port, pool_size); +// Close session +await session_pool.Close(); +``` -// Open Session -await session_pool.Open(false); +## 4. Full API Reference -// Create TimeSeries -await session_pool.CreateTimeSeries("root.test_group.test_device.ts1", TSDataType.TEXT, TSEncoding.PLAIN, Compressor.UNCOMPRESSED); -await session_pool.CreateTimeSeries("root.test_group.test_device.ts2", TSDataType.BOOLEAN, TSEncoding.PLAIN, Compressor.UNCOMPRESSED); -await session_pool.CreateTimeSeries("root.test_group.test_device.ts3", TSDataType.INT32, TSEncoding.PLAIN, Compressor.UNCOMPRESSED); +SessionPoolis a thread-safe connection pool that supports concurrent client requests. When pool_size=1, it behaves like a single session. -// Insert Record -var measures = new List{"ts1", "ts2", "ts3"}; -var values = new List { "test_text", true, (int)123 }; -var timestamp = 1; -var rowRecord = new RowRecord(timestamp, values, measures); -await session_pool.InsertRecordAsync("root.test_group.test_device", rowRecord); +### 4.1 Basic API -// Insert Tablet -var timestamp_lst = new List{ timestamp + 1 }; -var value_lst = new List {"iotdb", true, (int) 12}; -var tablet = new Tablet("root.test_group.test_device", measures, value_lst, timestamp_lst); -await session_pool.InsertTabletAsync(tablet); +| Method | Parameters | Description | Example | +| -------------- | --------------------------- | -------------- | -------------------------------- | +| Open | bool | Open session | session\_pool.Open(false) | +| Close | null | Close session | session\_pool.Close() | +| IsOpen | null | Check session status | session\_pool.IsOpen() | +| OpenDebugMode | LoggingConfiguration=null | Enable debug mode | session\_pool.OpenDebugMode() | +| CloseDebugMode | null | Disable debug mode | session\_pool.CloseDebugMode() | +| SetTimeZone | string | Set timezone | session\_pool.GetTimeZone() | +| GetTimeZone | null | Get timezone | session\_pool.GetTimeZone() | -// Close Session -await session_pool.Close(); -``` +### 4.2 Metadata API -## 6. **Row Record** +| Method | Parameters | Description | Example | +| ---------------------------- | ---------------------------------------------------------------------- | ---------------------- | ----------------------------------------------------------------------------------------------------------- | +| SetStorageGroup | string | Create a storage group | session\_pool.SetStorageGroup("root.97209\_TEST\_CSHARP\_CLIENT\_GROUP\_01") | +| CreateTimeSeries | string, TSDataType, TSEncoding, Compressor | Create a time series | session\_pool.InsertTabletsAsync(tablets) | +| CreateMultiTimeSeriesAsync | List, List , List , List | Create multiple time series | session\_pool.CreateMultiTimeSeriesAsync(ts\_path\_lst, data\_type\_lst, encoding\_lst, compressor\_lst); | +| CheckTimeSeriesExistsAsync | string | Check if a time series exists | session\_pool.CheckTimeSeriesExistsAsync(time series) | -- Encapsulate and abstract the `record` data in **IoTDB** -- e.g. +### 4.3 Write API - | timestamp | status | temperature | - | --------- | ------ | ----------- | - | 1 | 0 | 20 | +IoTDB C# client supports RowRecord (single-row) and Tablet (batch) writing -- Construction: +* RowRecord: For single-row insertion. -```csharp +```C# var rowRecord = new RowRecord(long timestamps, List values, List measurements); ``` -### 6.1 **Tablet** - -- A data structure similar to a table, containing several non empty data blocks of a device's rows。 -- e.g. - - | time | status | temperature | - | ---- | ------ | ----------- | - | 1 | 0 | 20 | - | 2 | 0 | 20 | - | 3 | 3 | 21 | +* Tablet: For batch insertion (device + multiple rows). -- Construction: - -```csharp +```C# var tablet = - Tablet(string deviceId, List measurements, List> values, List timestamps); + new Tablet(string deviceId, List measurements, List> values, List timestamps); ``` +#### 4.3.1 Record +| Method | Parameters | Description | Example | +| ------------------------------------- | ------------------------------- |--------------------------------------| ---------------------------------------------------------------------------------------------------------------------------------------------- | +| InsertRecordAsync | string, RowRecord | Insert a single record | session\_pool.InsertRecordAsync("root.97209\_TEST\_CSHARP\_CLIENT\_GROUP.TEST\_CSHARP\_CLIENT\_DEVICE", new RowRecord(1, values, measures)); | +| InsertRecordsAsync | List, List | Insert multiple records | session\_pool.InsertRecordsAsync(device\_id, rowRecords) | +| InsertRecordsOfOneDeviceAsync | string, List | Insert records for one device | session\_pool.InsertRecordsOfOneDeviceAsync(device\_id, rowRecords) | +| InsertRecordsOfOneDeviceSortedAsync | string, List | Insert sorted records for one device | session\_pool.InsertRecordsOfOneDeviceSortedAsync(deviceId, sortedRowRecords); | +| TestInsertRecordAsync | string, RowRecord | Test record insertion | session\_pool.TestInsertRecordAsync("root.97209\_TEST\_CSHARP\_CLIENT\_GROUP.TEST\_CSHARP\_CLIENT\_DEVICE", rowRecord) | +| TestInsertRecordsAsync | List, List | Test record insertion | session\_pool.TestInsertRecordsAsync(device\_id, rowRecords) | -## 7. **API** - -### 7.1 **Basic API** - -| api name | parameters | notes | use example | -| -------------- | ------------------------- | ------------------------ | ----------------------------- | -| Open | bool | open session | session_pool.Open(false) | -| Close | null | close session | session_pool.Close() | -| IsOpen | null | check if session is open | session_pool.IsOpen() | -| OpenDebugMode | LoggingConfiguration=null | open debug mode | session_pool.OpenDebugMode() | -| CloseDebugMode | null | close debug mode | session_pool.CloseDebugMode() | -| SetTimeZone | string | set time zone | session_pool.GetTimeZone() | -| GetTimeZone | null | get time zone | session_pool.GetTimeZone() | - -### 7.2 **Record API** - -| api name | parameters | notes | use example | -| ----------------------------------- | ----------------------------- | ----------------------------------- | ------------------------------------------------------------ | -| InsertRecordAsync | string, RowRecord | insert single record | session_pool.InsertRecordAsync("root.97209_TEST_CSHARP_CLIENT_GROUP.TEST_CSHARP_CLIENT_DEVICE", new RowRecord(1, values, measures)); | -| InsertRecordsAsync | List\, List\ | insert records | session_pool.InsertRecordsAsync(device_id, rowRecords) | -| InsertRecordsOfOneDeviceAsync | string, List\ | insert records of one device | session_pool.InsertRecordsOfOneDeviceAsync(device_id, rowRecords) | -| InsertRecordsOfOneDeviceSortedAsync | string, List\ | insert sorted records of one device | InsertRecordsOfOneDeviceSortedAsync(deviceId, sortedRowRecords); | -| TestInsertRecordAsync | string, RowRecord | test insert record | session_pool.TestInsertRecordAsync("root.97209_TEST_CSHARP_CLIENT_GROUP.TEST_CSHARP_CLIENT_DEVICE", rowRecord) | -| TestInsertRecordsAsync | List\, List\ | test insert record | session_pool.TestInsertRecordsAsync(device_id, rowRecords) | - -### 7.3 **Tablet API** - -| api name | parameters | notes | use example | -| ---------------------- | ------------ | -------------------- | -------------------------------------------- | -| InsertTabletAsync | Tablet | insert single tablet | session_pool.InsertTabletAsync(tablet) | -| InsertTabletsAsync | List\ | insert tablets | session_pool.InsertTabletsAsync(tablets) | -| TestInsertTabletAsync | Tablet | test insert tablet | session_pool.TestInsertTabletAsync(tablet) | -| TestInsertTabletsAsync | List\ | test insert tablets | session_pool.TestInsertTabletsAsync(tablets) | - -### 7.4 **SQL API** - -| api name | parameters | notes | use example | -| ----------------------------- | ---------- | ------------------------------ | ------------------------------------------------------------ | -| ExecuteQueryStatementAsync | string | execute sql query statement | session_pool.ExecuteQueryStatementAsync("select * from root.97209_TEST_CSHARP_CLIENT_GROUP.TEST_CSHARP_CLIENT_DEVICE where time<15"); | -| ExecuteNonQueryStatementAsync | string | execute sql nonquery statement | session_pool.ExecuteNonQueryStatementAsync( "create timeseries root.97209_TEST_CSHARP_CLIENT_GROUP.TEST_CSHARP_CLIENT_DEVICE.status with datatype=BOOLEAN,encoding=PLAIN") | - -### 7.5 **Scheam API** - -| api name | parameters | notes | use example | -| -------------------------- | ------------------------------------------------------------ | --------------------------- | ------------------------------------------------------------ | -| SetStorageGroup | string | set storage group | session_pool.SetStorageGroup("root.97209_TEST_CSHARP_CLIENT_GROUP_01") | -| CreateTimeSeries | string, TSDataType, TSEncoding, Compressor | create time series | session_pool.InsertTabletsAsync(tablets) | -| DeleteStorageGroupAsync | string | delete single storage group | session_pool.DeleteStorageGroupAsync("root.97209_TEST_CSHARP_CLIENT_GROUP_01") | -| DeleteStorageGroupsAsync | List\ | delete storage group | session_pool.DeleteStorageGroupAsync("root.97209_TEST_CSHARP_CLIENT_GROUP") | -| CreateMultiTimeSeriesAsync | List\, List\ , List\ , List\ | create multi time series | session_pool.CreateMultiTimeSeriesAsync(ts_path_lst, data_type_lst, encoding_lst, compressor_lst); | -| DeleteTimeSeriesAsync | List\ | delete time series | | -| DeleteTimeSeriesAsync | string | delete time series | | -| DeleteDataAsync | List\, long, long | delete data | session_pool.DeleteDataAsync(ts_path_lst, 2, 3) | - -### 7.6 **Other API** - -| api name | parameters | notes | use example | -| -------------------------- | ---------- | --------------------------- | ---------------------------------------------------- | -| CheckTimeSeriesExistsAsync | string | check if time series exists | session_pool.CheckTimeSeriesExistsAsync(time series) | - - +#### 4.3.2 Tablet -[e.g.](https://github.com/apache/iotdb-client-csharp/tree/main/samples/Apache.IoTDB.Samples) +| Method | Parameters | Description | Example | +| ------------------------ | -------------- | ------------------ | ----------------------------------------------- | +| InsertTabletAsync | Tablet | Insert a single tablet | session\_pool.InsertTabletAsync(tablet) | +| InsertTabletsAsync | List | Insert multiple tablets | session\_pool.InsertTabletsAsync(tablets) | +| TestInsertTabletAsync | Tablet | Test tablet insertion | session\_pool.TestInsertTabletAsync(tablet) | +| TestInsertTabletsAsync | List | Test tablet insertion | session\_pool.TestInsertTabletsAsync(tablets) | -## 8. SessionPool +### 4.4 Query API -To implement concurrent client requests, we provide a `SessionPool` for the native interface. Since `SessionPool` itself is a superset of `Session`, when `SessionPool` is a When the `pool_size` parameter is set to 1, it reverts to the original `Session` +| Method | Parameters | Description | Example | +| -------------------------------- | -------- | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| ExecuteQueryStatementAsync | string | Execute a query | session\_pool.ExecuteQueryStatementAsync("select \* from root.97209\_TEST\_CSHARP\_CLIENT\_GROUP.TEST\_CSHARP\_CLIENT\_DEVICE where time<15"); | +| ExecuteNonQueryStatementAsync| string | Execute a non-query statement | session\_pool.ExecuteNonQueryStatementAsync( "create timeseries root.97209\_TEST\_CSHARP\_CLIENT\_GROUP.TEST\_CSHARP\_CLIENT\_DEVICE.status with datatype=BOOLEAN,encoding=PLAIN") | -We use the `ConcurrentQueue` data structure to encapsulate a client queue to maintain multiple connections with the server. When the `Open()` interface is called, a specified number of clients are created in the queue, and synchronous access to the queue is achieved through the `System.Threading.Monitor` class. +### 4.5 Delete API -When a request occurs, it will try to find an idle client connection from the Connection pool. If there is no idle connection, the program will need to wait until there is an idle connection +| Method | Parameters | Description | Example | +| -------------------------- | -------------------------- |------------------------| -------------------------------------------------------------------------------------- | +| DeleteStorageGroupAsync | string | Delete a storage group | session\_pool.DeleteStorageGroupAsync("root.97209\_TEST\_CSHARP\_CLIENT\_GROUP\_01") | +| DeleteStorageGroupsAsync | List | Delete storage groups | session\_pool.DeleteStorageGroupAsync("root.97209\_TEST\_CSHARP\_CLIENT\_GROUP") | +| DeleteTimeSeriesAsync | List | Delete time series | session\_pool.DeleteTimeSeriesAsync(ts\_path\_lst) | +| DeleteTimeSeriesAsync | string | Delete time series | session\_pool.DeleteTimeSeriesAsync(ts\_path) | +| DeleteDataAsync | List, long, long | Delete data | session\_pool.DeleteDataAsync(ts\_path\_lst, 2, 3) | -When a connection is used up, it will automatically return to the pool and wait for the next time it is used up +## 5. Sample Code +For complete examples, refer to: [Apache.IoTDB.Samples](https://github.com/apache/iotdb-client-csharp/tree/main/samples/Apache.IoTDB.Samples) \ No newline at end of file diff --git a/src/UserGuide/V1.3.x/API/Programming-CSharp-Native-API.md b/src/UserGuide/V1.3.x/API/Programming-CSharp-Native-API.md index 6d8daaea7..a2d5ea4ec 100644 --- a/src/UserGuide/V1.3.x/API/Programming-CSharp-Native-API.md +++ b/src/UserGuide/V1.3.x/API/Programming-CSharp-Native-API.md @@ -18,186 +18,153 @@ # C# Native API -## Installation +## Environment Requirements -### Install from NuGet Package +* .NET SDK >= 5.0 or .NET Framework 4.x +* Thrift >= 0.14.1 +* NLog >= 4.7.9 -We have prepared Nuget Package for C# users. Users can directly install the client through .NET CLI. [The link of our NuGet Package is here](https://www.nuget.org/packages/Apache.IoTDB/). Run the following command in the command line to complete installation +## Dependency Installation -```sh -dotnet add package Apache.IoTDB -``` - -Note that the `Apache.IoTDB` package only supports versions greater than `.net framework 4.6.1`. - -## Prerequisites - -- .NET SDK Version >= 5.0 -- .NET Framework >= 4.6.1 - -## How to Use the Client (Quick Start) +You can use NuGet Package Manager, .NET CLI, or other tools to install the required packages. -Users can quickly get started by referring to the use cases under the Apache-IoTDB-Client-CSharp-UserCase directory. These use cases serve as a useful resource for getting familiar with the client's functionality and capabilities. +Using .NET CLI: -For those who wish to delve deeper into the client's usage and explore more advanced features, the samples directory contains additional code samples. +If you are using .NET 5.0 or later, run the following command to install the latest NuGet package -## Developer environment requirements for iotdb-client-csharp - -- .NET SDK Version >= 5.0 -- .NET Framework >= 4.6.1 -- ApacheThrift >= 0.14.1 -- NLog >= 4.7.9 - -### OS +```Bash +dotnet add package Apache.IoTDB +``` -- Linux, Macos or other unix-like OS -- Windows+bash(WSL, cygwin, Git Bash) +For .NET Framework 4.x, we provide a separate NuGet package. Run -### Command Line Tools +```Bash +dotnet add package Apache.IoTDB.framework +``` -- dotnet CLI -- Thrift +To install an older version, specify the version explicitly -## Basic interface description +```Bash +# Install v0.12.1.2 +dotnet add package Apache.IoTDB --version 0.12.1.2 +``` -The Session interface is semantically identical to other language clients +## Quick Start -```csharp -// Parameters -string host = "localhost"; -int port = 6667; -int pool_size = 2; +```C# +// Define parameters +string host = "localhost"; +int port = 6667; +int pool_size = 2; -// Init Session -var session_pool = new SessionPool(host, port, pool_size); +// Initialize session pool +var session_pool = new SessionPool(host, port, pool_size); -// Open Session -await session_pool.Open(false); +// Open session +await session_pool.Open(false); -// Create TimeSeries -await session_pool.CreateTimeSeries("root.test_group.test_device.ts1", TSDataType.TEXT, TSEncoding.PLAIN, Compressor.UNCOMPRESSED); -await session_pool.CreateTimeSeries("root.test_group.test_device.ts2", TSDataType.BOOLEAN, TSEncoding.PLAIN, Compressor.UNCOMPRESSED); -await session_pool.CreateTimeSeries("root.test_group.test_device.ts3", TSDataType.INT32, TSEncoding.PLAIN, Compressor.UNCOMPRESSED); +// Create time series +await session_pool.CreateTimeSeries("root.test_group.test_device.ts1", TSDataType.TEXT, TSEncoding.PLAIN, Compressor.UNCOMPRESSED); +await session_pool.CreateTimeSeries("root.test_group.test_device.ts2", TSDataType.BOOLEAN, TSEncoding.PLAIN, Compressor.UNCOMPRESSED); +await session_pool.CreateTimeSeries("root.test_group.test_device.ts3", TSDataType.INT32, TSEncoding.PLAIN, Compressor.UNCOMPRESSED); -// Insert Record -var measures = new List{"ts1", "ts2", "ts3"}; -var values = new List { "test_text", true, (int)123 }; -var timestamp = 1; -var rowRecord = new RowRecord(timestamp, values, measures); -await session_pool.InsertRecordAsync("root.test_group.test_device", rowRecord); +// Insert a record +var measures = new List{"ts1", "ts2", "ts3"}; +var values = new List { "test_text", true, (int)123 }; +var timestamp = 1; +var rowRecord = new RowRecord(timestamp, values, measures); +await session_pool.InsertRecordAsync("root.test_group.test_device", rowRecord); -// Insert Tablet -var timestamp_lst = new List{ timestamp + 1 }; -var value_lst = new List {"iotdb", true, (int) 12}; -var tablet = new Tablet("root.test_group.test_device", measures, value_lst, timestamp_lst); -await session_pool.InsertTabletAsync(tablet); +// Insert a tablet +var timestamp_lst = new List{ timestamp + 1 }; +var value_lst = new List {"iotdb", true, (int) 12}; +var tablet = new Tablet("root.test_group.test_device", measures, value_lst, timestamp_lst); +await session_pool.InsertTabletAsync(tablet); -// Close Session +// Close session await session_pool.Close(); ``` -## **Row Record** +## Full API Reference -- Encapsulate and abstract the `record` data in **IoTDB** -- e.g. +SessionPoolis a thread-safe connection pool that supports concurrent client requests. When pool_size=1, it behaves like a single session. - | timestamp | status | temperature | - | --------- | ------ | ----------- | - | 1 | 0 | 20 | +### Basic API -- Construction: +| Method | Parameters | Description | Example | +| -------------- | --------------------------- | -------------- | -------------------------------- | +| Open | bool | Open session | session\_pool.Open(false) | +| Close | null | Close session | session\_pool.Close() | +| IsOpen | null | Check session status | session\_pool.IsOpen() | +| OpenDebugMode | LoggingConfiguration=null | Enable debug mode | session\_pool.OpenDebugMode() | +| CloseDebugMode | null | Disable debug mode | session\_pool.CloseDebugMode() | +| SetTimeZone | string | Set timezone | session\_pool.GetTimeZone() | +| GetTimeZone | null | Get timezone | session\_pool.GetTimeZone() | -```csharp -var rowRecord = - new RowRecord(long timestamps, List values, List measurements); -``` +### Metadata API -### **Tablet** +| Method | Parameters | Description | Example | +| ---------------------------- | ---------------------------------------------------------------------- | ---------------------- | ----------------------------------------------------------------------------------------------------------- | +| SetStorageGroup | string | Create a storage group | session\_pool.SetStorageGroup("root.97209\_TEST\_CSHARP\_CLIENT\_GROUP\_01") | +| CreateTimeSeries | string, TSDataType, TSEncoding, Compressor | Create a time series | session\_pool.InsertTabletsAsync(tablets) | +| CreateMultiTimeSeriesAsync | List, List , List , List | Create multiple time series | session\_pool.CreateMultiTimeSeriesAsync(ts\_path\_lst, data\_type\_lst, encoding\_lst, compressor\_lst); | +| CheckTimeSeriesExistsAsync | string | Check if a time series exists | session\_pool.CheckTimeSeriesExistsAsync(time series) | -- A data structure similar to a table, containing several non empty data blocks of a device's rows。 -- e.g. +### Write API - | time | status | temperature | - | ---- | ------ | ----------- | - | 1 | 0 | 20 | - | 2 | 0 | 20 | - | 3 | 3 | 21 | +IoTDB C# client supports RowRecord (single-row) and Tablet (batch) writing -- Construction: +* RowRecord: For single-row insertion. -```csharp -var tablet = - Tablet(string deviceId, List measurements, List> values, List timestamps); +```C# +var rowRecord = + new RowRecord(long timestamps, List values, List measurements); ``` -## **API** - -### **Basic API** - -| api name | parameters | notes | use example | -| -------------- | ------------------------- | ------------------------ | ----------------------------- | -| Open | bool | open session | session_pool.Open(false) | -| Close | null | close session | session_pool.Close() | -| IsOpen | null | check if session is open | session_pool.IsOpen() | -| OpenDebugMode | LoggingConfiguration=null | open debug mode | session_pool.OpenDebugMode() | -| CloseDebugMode | null | close debug mode | session_pool.CloseDebugMode() | -| SetTimeZone | string | set time zone | session_pool.GetTimeZone() | -| GetTimeZone | null | get time zone | session_pool.GetTimeZone() | - -### **Record API** +* Tablet: For batch insertion (device + multiple rows). -| api name | parameters | notes | use example | -| ----------------------------------- | --------------------------------- | ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ | -| InsertRecordAsync | string, RowRecord | insert single record | session_pool.InsertRecordAsync("root.97209_TEST_CSHARP_CLIENT_GROUP.TEST_CSHARP_CLIENT_DEVICE", new RowRecord(1, values, measures)); | -| InsertRecordsAsync | List\, List\ | insert records | session_pool.InsertRecordsAsync(device_id, rowRecords) | -| InsertRecordsOfOneDeviceAsync | string, List\ | insert records of one device | session_pool.InsertRecordsOfOneDeviceAsync(device_id, rowRecords) | -| InsertRecordsOfOneDeviceSortedAsync | string, List\ | insert sorted records of one device | InsertRecordsOfOneDeviceSortedAsync(deviceId, sortedRowRecords); | -| TestInsertRecordAsync | string, RowRecord | test insert record | session_pool.TestInsertRecordAsync("root.97209_TEST_CSHARP_CLIENT_GROUP.TEST_CSHARP_CLIENT_DEVICE", rowRecord) | -| TestInsertRecordsAsync | List\, List\ | test insert record | session_pool.TestInsertRecordsAsync(device_id, rowRecords) | - -### **Tablet API** - -| api name | parameters | notes | use example | -| ---------------------- | -------------- | -------------------- | -------------------------------------------- | -| InsertTabletAsync | Tablet | insert single tablet | session_pool.InsertTabletAsync(tablet) | -| InsertTabletsAsync | List\ | insert tablets | session_pool.InsertTabletsAsync(tablets) | -| TestInsertTabletAsync | Tablet | test insert tablet | session_pool.TestInsertTabletAsync(tablet) | -| TestInsertTabletsAsync | List\ | test insert tablets | session_pool.TestInsertTabletsAsync(tablets) | - -### **SQL API** - -| api name | parameters | notes | use example | -| ----------------------------- | ---------- | ------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| ExecuteQueryStatementAsync | string | execute sql query statement | session_pool.ExecuteQueryStatementAsync("select \* from root.97209_TEST_CSHARP_CLIENT_GROUP.TEST_CSHARP_CLIENT_DEVICE where time<15"); | -| ExecuteNonQueryStatementAsync | string | execute sql nonquery statement | session_pool.ExecuteNonQueryStatementAsync( "create timeseries root.97209_TEST_CSHARP_CLIENT_GROUP.TEST_CSHARP_CLIENT_DEVICE.status with datatype=BOOLEAN,encoding=PLAIN") | +```C# +var tablet = + new Tablet(string deviceId, List measurements, List> values, List timestamps); +``` -### **Scheam API** +#### Record -| api name | parameters | notes | use example | -| -------------------------- | ---------------------------------------------------------------------------- | --------------------------- | -------------------------------------------------------------------------------------------------- | -| SetStorageGroup | string | set storage group | session_pool.SetStorageGroup("root.97209_TEST_CSHARP_CLIENT_GROUP_01") | -| CreateTimeSeries | string, TSDataType, TSEncoding, Compressor | create time series | session_pool.InsertTabletsAsync(tablets) | -| DeleteStorageGroupAsync | string | delete single storage group | session_pool.DeleteStorageGroupAsync("root.97209_TEST_CSHARP_CLIENT_GROUP_01") | -| DeleteStorageGroupsAsync | List\ | delete storage group | session_pool.DeleteStorageGroupAsync("root.97209_TEST_CSHARP_CLIENT_GROUP") | -| CreateMultiTimeSeriesAsync | List\, List\ , List\ , List\ | create multi time series | session_pool.CreateMultiTimeSeriesAsync(ts_path_lst, data_type_lst, encoding_lst, compressor_lst); | -| DeleteTimeSeriesAsync | List\ | delete time series | | -| DeleteTimeSeriesAsync | string | delete time series | | -| DeleteDataAsync | List\, long, long | delete data | session_pool.DeleteDataAsync(ts_path_lst, 2, 3) | +| Method | Parameters | Description | Example | +| ------------------------------------- | ------------------------------- |--------------------------------------| ---------------------------------------------------------------------------------------------------------------------------------------------- | +| InsertRecordAsync | string, RowRecord | Insert a single record | session\_pool.InsertRecordAsync("root.97209\_TEST\_CSHARP\_CLIENT\_GROUP.TEST\_CSHARP\_CLIENT\_DEVICE", new RowRecord(1, values, measures)); | +| InsertRecordsAsync | List, List | Insert multiple records | session\_pool.InsertRecordsAsync(device\_id, rowRecords) | +| InsertRecordsOfOneDeviceAsync | string, List | Insert records for one device | session\_pool.InsertRecordsOfOneDeviceAsync(device\_id, rowRecords) | +| InsertRecordsOfOneDeviceSortedAsync | string, List | Insert sorted records for one device | session\_pool.InsertRecordsOfOneDeviceSortedAsync(deviceId, sortedRowRecords); | +| TestInsertRecordAsync | string, RowRecord | Test record insertion | session\_pool.TestInsertRecordAsync("root.97209\_TEST\_CSHARP\_CLIENT\_GROUP.TEST\_CSHARP\_CLIENT\_DEVICE", rowRecord) | +| TestInsertRecordsAsync | List, List | Test record insertion | session\_pool.TestInsertRecordsAsync(device\_id, rowRecords) | -### **Other API** +#### Tablet -| api name | parameters | notes | use example | -| -------------------------- | ---------- | --------------------------- | ---------------------------------------------------- | -| CheckTimeSeriesExistsAsync | string | check if time series exists | session_pool.CheckTimeSeriesExistsAsync(time series) | +| Method | Parameters | Description | Example | +| ------------------------ | -------------- | ------------------ | ----------------------------------------------- | +| InsertTabletAsync | Tablet | Insert a single tablet | session\_pool.InsertTabletAsync(tablet) | +| InsertTabletsAsync | List | Insert multiple tablets | session\_pool.InsertTabletsAsync(tablets) | +| TestInsertTabletAsync | Tablet | Test tablet insertion | session\_pool.TestInsertTabletAsync(tablet) | +| TestInsertTabletsAsync | List | Test tablet insertion | session\_pool.TestInsertTabletsAsync(tablets) | -[e.g.](https://github.com/apache/iotdb-client-csharp/tree/main/samples/Apache.IoTDB.Samples) +### Query API -## SessionPool +| Method | Parameters | Description | Example | +| -------------------------------- | -------- | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| ExecuteQueryStatementAsync | string | Execute a query | session\_pool.ExecuteQueryStatementAsync("select \* from root.97209\_TEST\_CSHARP\_CLIENT\_GROUP.TEST\_CSHARP\_CLIENT\_DEVICE where time<15"); | +| ExecuteNonQueryStatementAsync| string | Execute a non-query statement | session\_pool.ExecuteNonQueryStatementAsync( "create timeseries root.97209\_TEST\_CSHARP\_CLIENT\_GROUP.TEST\_CSHARP\_CLIENT\_DEVICE.status with datatype=BOOLEAN,encoding=PLAIN") | -To implement concurrent client requests, we provide a `SessionPool` for the native interface. Since `SessionPool` itself is a superset of `Session`, when `SessionPool` is a When the `pool_size` parameter is set to 1, it reverts to the original `Session` +### Delete API -We use the `ConcurrentQueue` data structure to encapsulate a client queue to maintain multiple connections with the server. When the `Open()` interface is called, a specified number of clients are created in the queue, and synchronous access to the queue is achieved through the `System.Threading.Monitor` class. +| Method | Parameters | Description | Example | +| -------------------------- | -------------------------- |------------------------| -------------------------------------------------------------------------------------- | +| DeleteStorageGroupAsync | string | Delete a storage group | session\_pool.DeleteStorageGroupAsync("root.97209\_TEST\_CSHARP\_CLIENT\_GROUP\_01") | +| DeleteStorageGroupsAsync | List | Delete storage groups | session\_pool.DeleteStorageGroupAsync("root.97209\_TEST\_CSHARP\_CLIENT\_GROUP") | +| DeleteTimeSeriesAsync | List | Delete time series | session\_pool.DeleteTimeSeriesAsync(ts\_path\_lst) | +| DeleteTimeSeriesAsync | string | Delete time series | session\_pool.DeleteTimeSeriesAsync(ts\_path) | +| DeleteDataAsync | List, long, long | Delete data | session\_pool.DeleteDataAsync(ts\_path\_lst, 2, 3) | -When a request occurs, it will try to find an idle client connection from the Connection pool. If there is no idle connection, the program will need to wait until there is an idle connection +## Sample Code -When a connection is used up, it will automatically return to the pool and wait for the next time it is used up +For complete examples, refer to: [Apache.IoTDB.Samples](https://github.com/apache/iotdb-client-csharp/tree/main/samples/Apache.IoTDB.Samples) \ No newline at end of file diff --git a/src/UserGuide/dev-1.3/API/Programming-CSharp-Native-API.md b/src/UserGuide/dev-1.3/API/Programming-CSharp-Native-API.md index 6d8daaea7..a2d5ea4ec 100644 --- a/src/UserGuide/dev-1.3/API/Programming-CSharp-Native-API.md +++ b/src/UserGuide/dev-1.3/API/Programming-CSharp-Native-API.md @@ -18,186 +18,153 @@ # C# Native API -## Installation +## Environment Requirements -### Install from NuGet Package +* .NET SDK >= 5.0 or .NET Framework 4.x +* Thrift >= 0.14.1 +* NLog >= 4.7.9 -We have prepared Nuget Package for C# users. Users can directly install the client through .NET CLI. [The link of our NuGet Package is here](https://www.nuget.org/packages/Apache.IoTDB/). Run the following command in the command line to complete installation +## Dependency Installation -```sh -dotnet add package Apache.IoTDB -``` - -Note that the `Apache.IoTDB` package only supports versions greater than `.net framework 4.6.1`. - -## Prerequisites - -- .NET SDK Version >= 5.0 -- .NET Framework >= 4.6.1 - -## How to Use the Client (Quick Start) +You can use NuGet Package Manager, .NET CLI, or other tools to install the required packages. -Users can quickly get started by referring to the use cases under the Apache-IoTDB-Client-CSharp-UserCase directory. These use cases serve as a useful resource for getting familiar with the client's functionality and capabilities. +Using .NET CLI: -For those who wish to delve deeper into the client's usage and explore more advanced features, the samples directory contains additional code samples. +If you are using .NET 5.0 or later, run the following command to install the latest NuGet package -## Developer environment requirements for iotdb-client-csharp - -- .NET SDK Version >= 5.0 -- .NET Framework >= 4.6.1 -- ApacheThrift >= 0.14.1 -- NLog >= 4.7.9 - -### OS +```Bash +dotnet add package Apache.IoTDB +``` -- Linux, Macos or other unix-like OS -- Windows+bash(WSL, cygwin, Git Bash) +For .NET Framework 4.x, we provide a separate NuGet package. Run -### Command Line Tools +```Bash +dotnet add package Apache.IoTDB.framework +``` -- dotnet CLI -- Thrift +To install an older version, specify the version explicitly -## Basic interface description +```Bash +# Install v0.12.1.2 +dotnet add package Apache.IoTDB --version 0.12.1.2 +``` -The Session interface is semantically identical to other language clients +## Quick Start -```csharp -// Parameters -string host = "localhost"; -int port = 6667; -int pool_size = 2; +```C# +// Define parameters +string host = "localhost"; +int port = 6667; +int pool_size = 2; -// Init Session -var session_pool = new SessionPool(host, port, pool_size); +// Initialize session pool +var session_pool = new SessionPool(host, port, pool_size); -// Open Session -await session_pool.Open(false); +// Open session +await session_pool.Open(false); -// Create TimeSeries -await session_pool.CreateTimeSeries("root.test_group.test_device.ts1", TSDataType.TEXT, TSEncoding.PLAIN, Compressor.UNCOMPRESSED); -await session_pool.CreateTimeSeries("root.test_group.test_device.ts2", TSDataType.BOOLEAN, TSEncoding.PLAIN, Compressor.UNCOMPRESSED); -await session_pool.CreateTimeSeries("root.test_group.test_device.ts3", TSDataType.INT32, TSEncoding.PLAIN, Compressor.UNCOMPRESSED); +// Create time series +await session_pool.CreateTimeSeries("root.test_group.test_device.ts1", TSDataType.TEXT, TSEncoding.PLAIN, Compressor.UNCOMPRESSED); +await session_pool.CreateTimeSeries("root.test_group.test_device.ts2", TSDataType.BOOLEAN, TSEncoding.PLAIN, Compressor.UNCOMPRESSED); +await session_pool.CreateTimeSeries("root.test_group.test_device.ts3", TSDataType.INT32, TSEncoding.PLAIN, Compressor.UNCOMPRESSED); -// Insert Record -var measures = new List{"ts1", "ts2", "ts3"}; -var values = new List { "test_text", true, (int)123 }; -var timestamp = 1; -var rowRecord = new RowRecord(timestamp, values, measures); -await session_pool.InsertRecordAsync("root.test_group.test_device", rowRecord); +// Insert a record +var measures = new List{"ts1", "ts2", "ts3"}; +var values = new List { "test_text", true, (int)123 }; +var timestamp = 1; +var rowRecord = new RowRecord(timestamp, values, measures); +await session_pool.InsertRecordAsync("root.test_group.test_device", rowRecord); -// Insert Tablet -var timestamp_lst = new List{ timestamp + 1 }; -var value_lst = new List {"iotdb", true, (int) 12}; -var tablet = new Tablet("root.test_group.test_device", measures, value_lst, timestamp_lst); -await session_pool.InsertTabletAsync(tablet); +// Insert a tablet +var timestamp_lst = new List{ timestamp + 1 }; +var value_lst = new List {"iotdb", true, (int) 12}; +var tablet = new Tablet("root.test_group.test_device", measures, value_lst, timestamp_lst); +await session_pool.InsertTabletAsync(tablet); -// Close Session +// Close session await session_pool.Close(); ``` -## **Row Record** +## Full API Reference -- Encapsulate and abstract the `record` data in **IoTDB** -- e.g. +SessionPoolis a thread-safe connection pool that supports concurrent client requests. When pool_size=1, it behaves like a single session. - | timestamp | status | temperature | - | --------- | ------ | ----------- | - | 1 | 0 | 20 | +### Basic API -- Construction: +| Method | Parameters | Description | Example | +| -------------- | --------------------------- | -------------- | -------------------------------- | +| Open | bool | Open session | session\_pool.Open(false) | +| Close | null | Close session | session\_pool.Close() | +| IsOpen | null | Check session status | session\_pool.IsOpen() | +| OpenDebugMode | LoggingConfiguration=null | Enable debug mode | session\_pool.OpenDebugMode() | +| CloseDebugMode | null | Disable debug mode | session\_pool.CloseDebugMode() | +| SetTimeZone | string | Set timezone | session\_pool.GetTimeZone() | +| GetTimeZone | null | Get timezone | session\_pool.GetTimeZone() | -```csharp -var rowRecord = - new RowRecord(long timestamps, List values, List measurements); -``` +### Metadata API -### **Tablet** +| Method | Parameters | Description | Example | +| ---------------------------- | ---------------------------------------------------------------------- | ---------------------- | ----------------------------------------------------------------------------------------------------------- | +| SetStorageGroup | string | Create a storage group | session\_pool.SetStorageGroup("root.97209\_TEST\_CSHARP\_CLIENT\_GROUP\_01") | +| CreateTimeSeries | string, TSDataType, TSEncoding, Compressor | Create a time series | session\_pool.InsertTabletsAsync(tablets) | +| CreateMultiTimeSeriesAsync | List, List , List , List | Create multiple time series | session\_pool.CreateMultiTimeSeriesAsync(ts\_path\_lst, data\_type\_lst, encoding\_lst, compressor\_lst); | +| CheckTimeSeriesExistsAsync | string | Check if a time series exists | session\_pool.CheckTimeSeriesExistsAsync(time series) | -- A data structure similar to a table, containing several non empty data blocks of a device's rows。 -- e.g. +### Write API - | time | status | temperature | - | ---- | ------ | ----------- | - | 1 | 0 | 20 | - | 2 | 0 | 20 | - | 3 | 3 | 21 | +IoTDB C# client supports RowRecord (single-row) and Tablet (batch) writing -- Construction: +* RowRecord: For single-row insertion. -```csharp -var tablet = - Tablet(string deviceId, List measurements, List> values, List timestamps); +```C# +var rowRecord = + new RowRecord(long timestamps, List values, List measurements); ``` -## **API** - -### **Basic API** - -| api name | parameters | notes | use example | -| -------------- | ------------------------- | ------------------------ | ----------------------------- | -| Open | bool | open session | session_pool.Open(false) | -| Close | null | close session | session_pool.Close() | -| IsOpen | null | check if session is open | session_pool.IsOpen() | -| OpenDebugMode | LoggingConfiguration=null | open debug mode | session_pool.OpenDebugMode() | -| CloseDebugMode | null | close debug mode | session_pool.CloseDebugMode() | -| SetTimeZone | string | set time zone | session_pool.GetTimeZone() | -| GetTimeZone | null | get time zone | session_pool.GetTimeZone() | - -### **Record API** +* Tablet: For batch insertion (device + multiple rows). -| api name | parameters | notes | use example | -| ----------------------------------- | --------------------------------- | ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ | -| InsertRecordAsync | string, RowRecord | insert single record | session_pool.InsertRecordAsync("root.97209_TEST_CSHARP_CLIENT_GROUP.TEST_CSHARP_CLIENT_DEVICE", new RowRecord(1, values, measures)); | -| InsertRecordsAsync | List\, List\ | insert records | session_pool.InsertRecordsAsync(device_id, rowRecords) | -| InsertRecordsOfOneDeviceAsync | string, List\ | insert records of one device | session_pool.InsertRecordsOfOneDeviceAsync(device_id, rowRecords) | -| InsertRecordsOfOneDeviceSortedAsync | string, List\ | insert sorted records of one device | InsertRecordsOfOneDeviceSortedAsync(deviceId, sortedRowRecords); | -| TestInsertRecordAsync | string, RowRecord | test insert record | session_pool.TestInsertRecordAsync("root.97209_TEST_CSHARP_CLIENT_GROUP.TEST_CSHARP_CLIENT_DEVICE", rowRecord) | -| TestInsertRecordsAsync | List\, List\ | test insert record | session_pool.TestInsertRecordsAsync(device_id, rowRecords) | - -### **Tablet API** - -| api name | parameters | notes | use example | -| ---------------------- | -------------- | -------------------- | -------------------------------------------- | -| InsertTabletAsync | Tablet | insert single tablet | session_pool.InsertTabletAsync(tablet) | -| InsertTabletsAsync | List\ | insert tablets | session_pool.InsertTabletsAsync(tablets) | -| TestInsertTabletAsync | Tablet | test insert tablet | session_pool.TestInsertTabletAsync(tablet) | -| TestInsertTabletsAsync | List\ | test insert tablets | session_pool.TestInsertTabletsAsync(tablets) | - -### **SQL API** - -| api name | parameters | notes | use example | -| ----------------------------- | ---------- | ------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| ExecuteQueryStatementAsync | string | execute sql query statement | session_pool.ExecuteQueryStatementAsync("select \* from root.97209_TEST_CSHARP_CLIENT_GROUP.TEST_CSHARP_CLIENT_DEVICE where time<15"); | -| ExecuteNonQueryStatementAsync | string | execute sql nonquery statement | session_pool.ExecuteNonQueryStatementAsync( "create timeseries root.97209_TEST_CSHARP_CLIENT_GROUP.TEST_CSHARP_CLIENT_DEVICE.status with datatype=BOOLEAN,encoding=PLAIN") | +```C# +var tablet = + new Tablet(string deviceId, List measurements, List> values, List timestamps); +``` -### **Scheam API** +#### Record -| api name | parameters | notes | use example | -| -------------------------- | ---------------------------------------------------------------------------- | --------------------------- | -------------------------------------------------------------------------------------------------- | -| SetStorageGroup | string | set storage group | session_pool.SetStorageGroup("root.97209_TEST_CSHARP_CLIENT_GROUP_01") | -| CreateTimeSeries | string, TSDataType, TSEncoding, Compressor | create time series | session_pool.InsertTabletsAsync(tablets) | -| DeleteStorageGroupAsync | string | delete single storage group | session_pool.DeleteStorageGroupAsync("root.97209_TEST_CSHARP_CLIENT_GROUP_01") | -| DeleteStorageGroupsAsync | List\ | delete storage group | session_pool.DeleteStorageGroupAsync("root.97209_TEST_CSHARP_CLIENT_GROUP") | -| CreateMultiTimeSeriesAsync | List\, List\ , List\ , List\ | create multi time series | session_pool.CreateMultiTimeSeriesAsync(ts_path_lst, data_type_lst, encoding_lst, compressor_lst); | -| DeleteTimeSeriesAsync | List\ | delete time series | | -| DeleteTimeSeriesAsync | string | delete time series | | -| DeleteDataAsync | List\, long, long | delete data | session_pool.DeleteDataAsync(ts_path_lst, 2, 3) | +| Method | Parameters | Description | Example | +| ------------------------------------- | ------------------------------- |--------------------------------------| ---------------------------------------------------------------------------------------------------------------------------------------------- | +| InsertRecordAsync | string, RowRecord | Insert a single record | session\_pool.InsertRecordAsync("root.97209\_TEST\_CSHARP\_CLIENT\_GROUP.TEST\_CSHARP\_CLIENT\_DEVICE", new RowRecord(1, values, measures)); | +| InsertRecordsAsync | List, List | Insert multiple records | session\_pool.InsertRecordsAsync(device\_id, rowRecords) | +| InsertRecordsOfOneDeviceAsync | string, List | Insert records for one device | session\_pool.InsertRecordsOfOneDeviceAsync(device\_id, rowRecords) | +| InsertRecordsOfOneDeviceSortedAsync | string, List | Insert sorted records for one device | session\_pool.InsertRecordsOfOneDeviceSortedAsync(deviceId, sortedRowRecords); | +| TestInsertRecordAsync | string, RowRecord | Test record insertion | session\_pool.TestInsertRecordAsync("root.97209\_TEST\_CSHARP\_CLIENT\_GROUP.TEST\_CSHARP\_CLIENT\_DEVICE", rowRecord) | +| TestInsertRecordsAsync | List, List | Test record insertion | session\_pool.TestInsertRecordsAsync(device\_id, rowRecords) | -### **Other API** +#### Tablet -| api name | parameters | notes | use example | -| -------------------------- | ---------- | --------------------------- | ---------------------------------------------------- | -| CheckTimeSeriesExistsAsync | string | check if time series exists | session_pool.CheckTimeSeriesExistsAsync(time series) | +| Method | Parameters | Description | Example | +| ------------------------ | -------------- | ------------------ | ----------------------------------------------- | +| InsertTabletAsync | Tablet | Insert a single tablet | session\_pool.InsertTabletAsync(tablet) | +| InsertTabletsAsync | List | Insert multiple tablets | session\_pool.InsertTabletsAsync(tablets) | +| TestInsertTabletAsync | Tablet | Test tablet insertion | session\_pool.TestInsertTabletAsync(tablet) | +| TestInsertTabletsAsync | List | Test tablet insertion | session\_pool.TestInsertTabletsAsync(tablets) | -[e.g.](https://github.com/apache/iotdb-client-csharp/tree/main/samples/Apache.IoTDB.Samples) +### Query API -## SessionPool +| Method | Parameters | Description | Example | +| -------------------------------- | -------- | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| ExecuteQueryStatementAsync | string | Execute a query | session\_pool.ExecuteQueryStatementAsync("select \* from root.97209\_TEST\_CSHARP\_CLIENT\_GROUP.TEST\_CSHARP\_CLIENT\_DEVICE where time<15"); | +| ExecuteNonQueryStatementAsync| string | Execute a non-query statement | session\_pool.ExecuteNonQueryStatementAsync( "create timeseries root.97209\_TEST\_CSHARP\_CLIENT\_GROUP.TEST\_CSHARP\_CLIENT\_DEVICE.status with datatype=BOOLEAN,encoding=PLAIN") | -To implement concurrent client requests, we provide a `SessionPool` for the native interface. Since `SessionPool` itself is a superset of `Session`, when `SessionPool` is a When the `pool_size` parameter is set to 1, it reverts to the original `Session` +### Delete API -We use the `ConcurrentQueue` data structure to encapsulate a client queue to maintain multiple connections with the server. When the `Open()` interface is called, a specified number of clients are created in the queue, and synchronous access to the queue is achieved through the `System.Threading.Monitor` class. +| Method | Parameters | Description | Example | +| -------------------------- | -------------------------- |------------------------| -------------------------------------------------------------------------------------- | +| DeleteStorageGroupAsync | string | Delete a storage group | session\_pool.DeleteStorageGroupAsync("root.97209\_TEST\_CSHARP\_CLIENT\_GROUP\_01") | +| DeleteStorageGroupsAsync | List | Delete storage groups | session\_pool.DeleteStorageGroupAsync("root.97209\_TEST\_CSHARP\_CLIENT\_GROUP") | +| DeleteTimeSeriesAsync | List | Delete time series | session\_pool.DeleteTimeSeriesAsync(ts\_path\_lst) | +| DeleteTimeSeriesAsync | string | Delete time series | session\_pool.DeleteTimeSeriesAsync(ts\_path) | +| DeleteDataAsync | List, long, long | Delete data | session\_pool.DeleteDataAsync(ts\_path\_lst, 2, 3) | -When a request occurs, it will try to find an idle client connection from the Connection pool. If there is no idle connection, the program will need to wait until there is an idle connection +## Sample Code -When a connection is used up, it will automatically return to the pool and wait for the next time it is used up +For complete examples, refer to: [Apache.IoTDB.Samples](https://github.com/apache/iotdb-client-csharp/tree/main/samples/Apache.IoTDB.Samples) \ No newline at end of file diff --git a/src/UserGuide/latest/API/Programming-CSharp-Native-API.md b/src/UserGuide/latest/API/Programming-CSharp-Native-API.md index 2a85b3c32..eab64cbab 100644 --- a/src/UserGuide/latest/API/Programming-CSharp-Native-API.md +++ b/src/UserGuide/latest/API/Programming-CSharp-Native-API.md @@ -1,213 +1,170 @@ # C# Native API -## 1. Installation +## 1. Environment Requirements -### 1.1 Install from NuGet Package +* .NET SDK >= 5.0 or .NET Framework 4.x +* Thrift >= 0.14.1 +* NLog >= 4.7.9 -We have prepared Nuget Package for C# users. Users can directly install the client through .NET CLI. [The link of our NuGet Package is here](https://www.nuget.org/packages/Apache.IoTDB/). Run the following command in the command line to complete installation - -```sh -dotnet add package Apache.IoTDB -``` +## 2. Dependency Installation -Note that the `Apache.IoTDB` package only supports versions greater than `.net framework 4.6.1`. +You can use NuGet Package Manager, .NET CLI, or other tools to install the required packages. -## 2. Prerequisites +Using .NET CLI: - .NET SDK Version >= 5.0 - .NET Framework >= 4.6.1 +If you are using .NET 5.0 or later, run the following command to install the latest NuGet package -## 3. How to Use the Client (Quick Start) +```Bash +dotnet add package Apache.IoTDB +``` -Users can quickly get started by referring to the use cases under the Apache-IoTDB-Client-CSharp-UserCase directory. These use cases serve as a useful resource for getting familiar with the client's functionality and capabilities. +For .NET Framework 4.x, we provide a separate NuGet package. Run -For those who wish to delve deeper into the client's usage and explore more advanced features, the samples directory contains additional code samples. +```Bash +dotnet add package Apache.IoTDB.framework +``` -## 4. Developer environment requirements for iotdb-client-csharp +To install an older version, specify the version explicitly -``` -.NET SDK Version >= 5.0 -.NET Framework >= 4.6.1 -ApacheThrift >= 0.14.1 -NLog >= 4.7.9 +```Bash +# Install v0.12.1.2 +dotnet add package Apache.IoTDB --version 0.12.1.2 ``` -### 4.1 OS +## 3. Quick Start -* Linux, Macos or other unix-like OS -* Windows+bash(WSL, cygwin, Git Bash) +```C# +// Define parameters +string host = "localhost"; +int port = 6667; +int pool_size = 2; -### 4.2 Command Line Tools +// Initialize session pool +var session_pool = new SessionPool(host, port, pool_size); -* dotnet CLI -* Thrift +// Open session +await session_pool.Open(false); -## 5. Basic interface description +// Create time series +await session_pool.CreateTimeSeries("root.test_group.test_device.ts1", TSDataType.TEXT, TSEncoding.PLAIN, Compressor.UNCOMPRESSED); +await session_pool.CreateTimeSeries("root.test_group.test_device.ts2", TSDataType.BOOLEAN, TSEncoding.PLAIN, Compressor.UNCOMPRESSED); +await session_pool.CreateTimeSeries("root.test_group.test_device.ts3", TSDataType.INT32, TSEncoding.PLAIN, Compressor.UNCOMPRESSED); -The Session interface is semantically identical to other language clients +// Insert a record +var measures = new List{"ts1", "ts2", "ts3"}; +var values = new List { "test_text", true, (int)123 }; +var timestamp = 1; +var rowRecord = new RowRecord(timestamp, values, measures); +await session_pool.InsertRecordAsync("root.test_group.test_device", rowRecord); -```csharp -// Parameters -string host = "localhost"; -int port = 6667; -int pool_size = 2; +// Insert a tablet +var timestamp_lst = new List{ timestamp + 1 }; +var value_lst = new List {"iotdb", true, (int) 12}; +var tablet = new Tablet("root.test_group.test_device", measures, value_lst, timestamp_lst); +await session_pool.InsertTabletAsync(tablet); -// Init Session -var session_pool = new SessionPool(host, port, pool_size); +// Close session +await session_pool.Close(); +``` -// Open Session -await session_pool.Open(false); +## 4. Full API Reference -// Create TimeSeries -await session_pool.CreateTimeSeries("root.test_group.test_device.ts1", TSDataType.TEXT, TSEncoding.PLAIN, Compressor.UNCOMPRESSED); -await session_pool.CreateTimeSeries("root.test_group.test_device.ts2", TSDataType.BOOLEAN, TSEncoding.PLAIN, Compressor.UNCOMPRESSED); -await session_pool.CreateTimeSeries("root.test_group.test_device.ts3", TSDataType.INT32, TSEncoding.PLAIN, Compressor.UNCOMPRESSED); +SessionPoolis a thread-safe connection pool that supports concurrent client requests. When pool_size=1, it behaves like a single session. -// Insert Record -var measures = new List{"ts1", "ts2", "ts3"}; -var values = new List { "test_text", true, (int)123 }; -var timestamp = 1; -var rowRecord = new RowRecord(timestamp, values, measures); -await session_pool.InsertRecordAsync("root.test_group.test_device", rowRecord); +### 4.1 Basic API -// Insert Tablet -var timestamp_lst = new List{ timestamp + 1 }; -var value_lst = new List {"iotdb", true, (int) 12}; -var tablet = new Tablet("root.test_group.test_device", measures, value_lst, timestamp_lst); -await session_pool.InsertTabletAsync(tablet); +| Method | Parameters | Description | Example | +| -------------- | --------------------------- | -------------- | -------------------------------- | +| Open | bool | Open session | session\_pool.Open(false) | +| Close | null | Close session | session\_pool.Close() | +| IsOpen | null | Check session status | session\_pool.IsOpen() | +| OpenDebugMode | LoggingConfiguration=null | Enable debug mode | session\_pool.OpenDebugMode() | +| CloseDebugMode | null | Disable debug mode | session\_pool.CloseDebugMode() | +| SetTimeZone | string | Set timezone | session\_pool.GetTimeZone() | +| GetTimeZone | null | Get timezone | session\_pool.GetTimeZone() | -// Close Session -await session_pool.Close(); -``` +### 4.2 Metadata API -## 6. **Row Record** +| Method | Parameters | Description | Example | +| ---------------------------- | ---------------------------------------------------------------------- | ---------------------- | ----------------------------------------------------------------------------------------------------------- | +| SetStorageGroup | string | Create a storage group | session\_pool.SetStorageGroup("root.97209\_TEST\_CSHARP\_CLIENT\_GROUP\_01") | +| CreateTimeSeries | string, TSDataType, TSEncoding, Compressor | Create a time series | session\_pool.InsertTabletsAsync(tablets) | +| CreateMultiTimeSeriesAsync | List, List , List , List | Create multiple time series | session\_pool.CreateMultiTimeSeriesAsync(ts\_path\_lst, data\_type\_lst, encoding\_lst, compressor\_lst); | +| CheckTimeSeriesExistsAsync | string | Check if a time series exists | session\_pool.CheckTimeSeriesExistsAsync(time series) | -- Encapsulate and abstract the `record` data in **IoTDB** -- e.g. +### 4.3 Write API - | timestamp | status | temperature | - | --------- | ------ | ----------- | - | 1 | 0 | 20 | +IoTDB C# client supports RowRecord (single-row) and Tablet (batch) writing -- Construction: +* RowRecord: For single-row insertion. -```csharp +```C# var rowRecord = new RowRecord(long timestamps, List values, List measurements); ``` -### 6.1 **Tablet** - -- A data structure similar to a table, containing several non empty data blocks of a device's rows。 -- e.g. - - | time | status | temperature | - | ---- | ------ | ----------- | - | 1 | 0 | 20 | - | 2 | 0 | 20 | - | 3 | 3 | 21 | +* Tablet: For batch insertion (device + multiple rows). -- Construction: - -```csharp +```C# var tablet = - Tablet(string deviceId, List measurements, List> values, List timestamps); + new Tablet(string deviceId, List measurements, List> values, List timestamps); ``` +#### 4.3.1 Record +| Method | Parameters | Description | Example | +| ------------------------------------- | ------------------------------- |--------------------------------------| ---------------------------------------------------------------------------------------------------------------------------------------------- | +| InsertRecordAsync | string, RowRecord | Insert a single record | session\_pool.InsertRecordAsync("root.97209\_TEST\_CSHARP\_CLIENT\_GROUP.TEST\_CSHARP\_CLIENT\_DEVICE", new RowRecord(1, values, measures)); | +| InsertRecordsAsync | List, List | Insert multiple records | session\_pool.InsertRecordsAsync(device\_id, rowRecords) | +| InsertRecordsOfOneDeviceAsync | string, List | Insert records for one device | session\_pool.InsertRecordsOfOneDeviceAsync(device\_id, rowRecords) | +| InsertRecordsOfOneDeviceSortedAsync | string, List | Insert sorted records for one device | session\_pool.InsertRecordsOfOneDeviceSortedAsync(deviceId, sortedRowRecords); | +| TestInsertRecordAsync | string, RowRecord | Test record insertion | session\_pool.TestInsertRecordAsync("root.97209\_TEST\_CSHARP\_CLIENT\_GROUP.TEST\_CSHARP\_CLIENT\_DEVICE", rowRecord) | +| TestInsertRecordsAsync | List, List | Test record insertion | session\_pool.TestInsertRecordsAsync(device\_id, rowRecords) | -## 7. **API** - -### 7.1 **Basic API** - -| api name | parameters | notes | use example | -| -------------- | ------------------------- | ------------------------ | ----------------------------- | -| Open | bool | open session | session_pool.Open(false) | -| Close | null | close session | session_pool.Close() | -| IsOpen | null | check if session is open | session_pool.IsOpen() | -| OpenDebugMode | LoggingConfiguration=null | open debug mode | session_pool.OpenDebugMode() | -| CloseDebugMode | null | close debug mode | session_pool.CloseDebugMode() | -| SetTimeZone | string | set time zone | session_pool.GetTimeZone() | -| GetTimeZone | null | get time zone | session_pool.GetTimeZone() | - -### 7.2 **Record API** - -| api name | parameters | notes | use example | -| ----------------------------------- | ----------------------------- | ----------------------------------- | ------------------------------------------------------------ | -| InsertRecordAsync | string, RowRecord | insert single record | session_pool.InsertRecordAsync("root.97209_TEST_CSHARP_CLIENT_GROUP.TEST_CSHARP_CLIENT_DEVICE", new RowRecord(1, values, measures)); | -| InsertRecordsAsync | List\, List\ | insert records | session_pool.InsertRecordsAsync(device_id, rowRecords) | -| InsertRecordsOfOneDeviceAsync | string, List\ | insert records of one device | session_pool.InsertRecordsOfOneDeviceAsync(device_id, rowRecords) | -| InsertRecordsOfOneDeviceSortedAsync | string, List\ | insert sorted records of one device | InsertRecordsOfOneDeviceSortedAsync(deviceId, sortedRowRecords); | -| TestInsertRecordAsync | string, RowRecord | test insert record | session_pool.TestInsertRecordAsync("root.97209_TEST_CSHARP_CLIENT_GROUP.TEST_CSHARP_CLIENT_DEVICE", rowRecord) | -| TestInsertRecordsAsync | List\, List\ | test insert record | session_pool.TestInsertRecordsAsync(device_id, rowRecords) | - -### 7.3 **Tablet API** - -| api name | parameters | notes | use example | -| ---------------------- | ------------ | -------------------- | -------------------------------------------- | -| InsertTabletAsync | Tablet | insert single tablet | session_pool.InsertTabletAsync(tablet) | -| InsertTabletsAsync | List\ | insert tablets | session_pool.InsertTabletsAsync(tablets) | -| TestInsertTabletAsync | Tablet | test insert tablet | session_pool.TestInsertTabletAsync(tablet) | -| TestInsertTabletsAsync | List\ | test insert tablets | session_pool.TestInsertTabletsAsync(tablets) | - -### 7.4 **SQL API** - -| api name | parameters | notes | use example | -| ----------------------------- | ---------- | ------------------------------ | ------------------------------------------------------------ | -| ExecuteQueryStatementAsync | string | execute sql query statement | session_pool.ExecuteQueryStatementAsync("select * from root.97209_TEST_CSHARP_CLIENT_GROUP.TEST_CSHARP_CLIENT_DEVICE where time<15"); | -| ExecuteNonQueryStatementAsync | string | execute sql nonquery statement | session_pool.ExecuteNonQueryStatementAsync( "create timeseries root.97209_TEST_CSHARP_CLIENT_GROUP.TEST_CSHARP_CLIENT_DEVICE.status with datatype=BOOLEAN,encoding=PLAIN") | - -### 7.5 **Scheam API** - -| api name | parameters | notes | use example | -| -------------------------- | ------------------------------------------------------------ | --------------------------- | ------------------------------------------------------------ | -| SetStorageGroup | string | set storage group | session_pool.SetStorageGroup("root.97209_TEST_CSHARP_CLIENT_GROUP_01") | -| CreateTimeSeries | string, TSDataType, TSEncoding, Compressor | create time series | session_pool.InsertTabletsAsync(tablets) | -| DeleteStorageGroupAsync | string | delete single storage group | session_pool.DeleteStorageGroupAsync("root.97209_TEST_CSHARP_CLIENT_GROUP_01") | -| DeleteStorageGroupsAsync | List\ | delete storage group | session_pool.DeleteStorageGroupAsync("root.97209_TEST_CSHARP_CLIENT_GROUP") | -| CreateMultiTimeSeriesAsync | List\, List\ , List\ , List\ | create multi time series | session_pool.CreateMultiTimeSeriesAsync(ts_path_lst, data_type_lst, encoding_lst, compressor_lst); | -| DeleteTimeSeriesAsync | List\ | delete time series | | -| DeleteTimeSeriesAsync | string | delete time series | | -| DeleteDataAsync | List\, long, long | delete data | session_pool.DeleteDataAsync(ts_path_lst, 2, 3) | - -### 7.6 **Other API** - -| api name | parameters | notes | use example | -| -------------------------- | ---------- | --------------------------- | ---------------------------------------------------- | -| CheckTimeSeriesExistsAsync | string | check if time series exists | session_pool.CheckTimeSeriesExistsAsync(time series) | - - +#### 4.3.2 Tablet -[e.g.](https://github.com/apache/iotdb-client-csharp/tree/main/samples/Apache.IoTDB.Samples) +| Method | Parameters | Description | Example | +| ------------------------ | -------------- | ------------------ | ----------------------------------------------- | +| InsertTabletAsync | Tablet | Insert a single tablet | session\_pool.InsertTabletAsync(tablet) | +| InsertTabletsAsync | List | Insert multiple tablets | session\_pool.InsertTabletsAsync(tablets) | +| TestInsertTabletAsync | Tablet | Test tablet insertion | session\_pool.TestInsertTabletAsync(tablet) | +| TestInsertTabletsAsync | List | Test tablet insertion | session\_pool.TestInsertTabletsAsync(tablets) | -## 8. SessionPool +### 4.4 Query API -To implement concurrent client requests, we provide a `SessionPool` for the native interface. Since `SessionPool` itself is a superset of `Session`, when `SessionPool` is a When the `pool_size` parameter is set to 1, it reverts to the original `Session` +| Method | Parameters | Description | Example | +| -------------------------------- | -------- | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| ExecuteQueryStatementAsync | string | Execute a query | session\_pool.ExecuteQueryStatementAsync("select \* from root.97209\_TEST\_CSHARP\_CLIENT\_GROUP.TEST\_CSHARP\_CLIENT\_DEVICE where time<15"); | +| ExecuteNonQueryStatementAsync| string | Execute a non-query statement | session\_pool.ExecuteNonQueryStatementAsync( "create timeseries root.97209\_TEST\_CSHARP\_CLIENT\_GROUP.TEST\_CSHARP\_CLIENT\_DEVICE.status with datatype=BOOLEAN,encoding=PLAIN") | -We use the `ConcurrentQueue` data structure to encapsulate a client queue to maintain multiple connections with the server. When the `Open()` interface is called, a specified number of clients are created in the queue, and synchronous access to the queue is achieved through the `System.Threading.Monitor` class. +### 4.5 Delete API -When a request occurs, it will try to find an idle client connection from the Connection pool. If there is no idle connection, the program will need to wait until there is an idle connection +| Method | Parameters | Description | Example | +| -------------------------- | -------------------------- |------------------------| -------------------------------------------------------------------------------------- | +| DeleteStorageGroupAsync | string | Delete a storage group | session\_pool.DeleteStorageGroupAsync("root.97209\_TEST\_CSHARP\_CLIENT\_GROUP\_01") | +| DeleteStorageGroupsAsync | List | Delete storage groups | session\_pool.DeleteStorageGroupAsync("root.97209\_TEST\_CSHARP\_CLIENT\_GROUP") | +| DeleteTimeSeriesAsync | List | Delete time series | session\_pool.DeleteTimeSeriesAsync(ts\_path\_lst) | +| DeleteTimeSeriesAsync | string | Delete time series | session\_pool.DeleteTimeSeriesAsync(ts\_path) | +| DeleteDataAsync | List, long, long | Delete data | session\_pool.DeleteDataAsync(ts\_path\_lst, 2, 3) | -When a connection is used up, it will automatically return to the pool and wait for the next time it is used up +## 5. Sample Code +For complete examples, refer to: [Apache.IoTDB.Samples](https://github.com/apache/iotdb-client-csharp/tree/main/samples/Apache.IoTDB.Samples) \ No newline at end of file diff --git a/src/zh/UserGuide/Master/Tree/API/Programming-CSharp-Native-API.md b/src/zh/UserGuide/Master/Tree/API/Programming-CSharp-Native-API.md index d8997bff6..40f0b49b3 100644 --- a/src/zh/UserGuide/Master/Tree/API/Programming-CSharp-Native-API.md +++ b/src/zh/UserGuide/Master/Tree/API/Programming-CSharp-Native-API.md @@ -21,34 +21,32 @@ # C# 原生接口 -## 1. 依赖 +## 1. 环境要求 -- .NET SDK >= 5.0 或 .NET Framework 4.x -- Thrift >= 0.14.1 -- NLog >= 4.7.9 +* .NET SDK >= 5.0 或 .NET Framework 4.x +* Thrift >= 0.14.1 +* NLog >= 4.7.9 -## 2. 安装 +## 2. 依赖安装 您可以使用 NuGet Package Manager, .NET CLI等工具来安装,以 .NET CLI为例 -如果您使用的是\.NET 5.0 或者更高版本的SDK,输入如下命令即可安装最新的NuGet包 +如果您使用的是.NET 5.0 或者更高版本的SDK,输入如下命令即可安装最新的NuGet包 -``` +```Bash dotnet add package Apache.IoTDB ``` 如果您想安装更早版本的客户端,只需要指定版本即可 -```bash +```Bash # 安装0.12.1.2版本的客户端 dotnet add package Apache.IoTDB --version 0.12.1.2 ``` -## 3. 基本接口说明 - -Session接口在语义上和其他语言客户端相同 +## 3. 快速入门 -```csharp +```C# // 参数定义 string host = "localhost"; int port = 6667; @@ -82,187 +80,87 @@ await session_pool.InsertTabletAsync(tablet); await session_pool.Close(); ``` -## 4. **Row Record** +## 4. 全量接口说明 -- 对**IoTDB**中的`record`数据进行封装和抽象。 -- 示例: +SessionPool 连接池支持并发客户端请求,线程安全。当 `pool_size`设为 1 时,其行为等同于单个 session。推荐使用 SessionPool ,作为实现与数据库交互的核心接口,SessionPool 集成了丰富的方法,支持数据写入、查询以及元数据操作等功能,详细介绍见下文。 - | timestamp | status | temperature | - | --------- | ------ | ----------- | - | 1 | 0 | 20 | +### 4.1 基础接口 -- 构造方法: +| 方法名 | 参数 | 描述 | 示例 | +| ---------------- | --------------------------- | -------------- | -------------------------------- | +| Open | bool | 打开会话 | session\_pool.Open(false) | +| Close | null | 关闭会话 | session\_pool.Close() | +| IsOpen | null | 查看会话状态 | session\_pool.IsOpen() | +| OpenDebugMode | LoggingConfiguration=null | 启用调试模式 | session\_pool.OpenDebugMode() | +| CloseDebugMode | null | 禁用调试模式 | session\_pool.CloseDebugMode() | +| SetTimeZone | string | 设置时区 | session\_pool.GetTimeZone() | +| GetTimeZone | null | 获取时区 | session\_pool.GetTimeZone() | -```csharp -var rowRecord = - new RowRecord(long timestamps, List values, List measurements); -``` +### 4.2 元数据接口 -### 4.1 **Tablet** +| 方法名 | 参数 | 描述 | 示例 | +| ---------------------------- | ---------------------------------------------------------------------- | ---------------------- | ----------------------------------------------------------------------------------------------------------- | +| SetStorageGroup | string | (创建)存储组 | session\_pool.SetStorageGroup("root.97209\_TEST\_CSHARP\_CLIENT\_GROUP\_01") | +| CreateTimeSeries | string, TSDataType, TSEncoding, Compressor | 创建时间序列 | session\_pool.InsertTabletsAsync(tablets) | +| CreateMultiTimeSeriesAsync | List, List , List , List | 创建多个时间序列 | session\_pool.CreateMultiTimeSeriesAsync(ts\_path\_lst, data\_type\_lst, encoding\_lst, compressor\_lst); | +| CheckTimeSeriesExistsAsync | string | 查看时间序列是否存在 | session\_pool.CheckTimeSeriesExistsAsync(time series) | -- 一种类似于表格的数据结构,包含一个设备的若干行非空数据块。 -- 示例: +### 4.3 写入接口 - | time | status | temperature | - | ---- | ------ | ----------- | - | 1 | 0 | 20 | - | 2 | 0 | 20 | - | 3 | 3 | 21 | +C# 原生接口支持通过 Record 和 Tablet 两种方式进行数据写入: -- 构造方法: +* RowRecord 是对 IoTDB 中的`record`数据进行封装和抽象,适合单行数据写入的场景,其构造方法如下 -```csharp -var tablet = - Tablet(string deviceId, List measurements, List> values, List timestamps); +```C# +var rowRecord = + new RowRecord(long timestamps, List values, List measurements); ``` +* Tablet 是一种类似于表格的数据结构,适合一个设备若干行非空数据块写入的场景,其构造方法如下 +```C# +var tablet = + new Tablet(string deviceId, List measurements, List> values, List timestamps); +``` -## 5. **API** - -### 5.1 **基础接口** - -| api name | parameters | notes | use example | -| -------------- | ------------------------- | ------------------------ | ----------------------------- | -| Open | bool | open session | session_pool.Open(false) | -| Close | null | close session | session_pool.Close() | -| IsOpen | null | check if session is open | session_pool.IsOpen() | -| OpenDebugMode | LoggingConfiguration=null | open debug mode | session_pool.OpenDebugMode() | -| CloseDebugMode | null | close debug mode | session_pool.CloseDebugMode() | -| SetTimeZone | string | set time zone | session_pool.GetTimeZone() | -| GetTimeZone | null | get time zone | session_pool.GetTimeZone() | - -### 5.2 **Record相关接口** - -| api name | parameters | notes | use example | -| ----------------------------------- | ----------------------------- | ----------------------------------- | ------------------------------------------------------------ | -| InsertRecordAsync | string, RowRecord | insert single record | session_pool.InsertRecordAsync("root.97209_TEST_CSHARP_CLIENT_GROUP.TEST_CSHARP_CLIENT_DEVICE", new RowRecord(1, values, measures)); | -| InsertRecordsAsync | List\, List\ | insert records | session_pool.InsertRecordsAsync(device_id, rowRecords) | -| InsertRecordsOfOneDeviceAsync | string, List\ | insert records of one device | session_pool.InsertRecordsOfOneDeviceAsync(device_id, rowRecords) | -| InsertRecordsOfOneDeviceSortedAsync | string, List\ | insert sorted records of one device | InsertRecordsOfOneDeviceSortedAsync(deviceId, sortedRowRecords); | -| TestInsertRecordAsync | string, RowRecord | test insert record | session_pool.TestInsertRecordAsync("root.97209_TEST_CSHARP_CLIENT_GROUP.TEST_CSHARP_CLIENT_DEVICE", rowRecord) | -| TestInsertRecordsAsync | List\, List\ | test insert record | session_pool.TestInsertRecordsAsync(device_id, rowRecords) | - -### 5.3 **Tablet相关接口** - -| api name | parameters | notes | use example | -| ---------------------- | ------------ | -------------------- | -------------------------------------------- | -| InsertTabletAsync | Tablet | insert single tablet | session_pool.InsertTabletAsync(tablet) | -| InsertTabletsAsync | List\ | insert tablets | session_pool.InsertTabletsAsync(tablets) | -| TestInsertTabletAsync | Tablet | test insert tablet | session_pool.TestInsertTabletAsync(tablet) | -| TestInsertTabletsAsync | List\ | test insert tablets | session_pool.TestInsertTabletsAsync(tablets) | - -### 5.4 **SQL语句接口** - -| api name | parameters | notes | use example | -| ----------------------------- | ---------- | ------------------------------ | ------------------------------------------------------------ | -| ExecuteQueryStatementAsync | string | execute sql query statement | session_pool.ExecuteQueryStatementAsync("select * from root.97209_TEST_CSHARP_CLIENT_GROUP.TEST_CSHARP_CLIENT_DEVICE where time<15"); | -| ExecuteNonQueryStatementAsync | string | execute sql nonquery statement | session_pool.ExecuteNonQueryStatementAsync( "create timeseries root.97209_TEST_CSHARP_CLIENT_GROUP.TEST_CSHARP_CLIENT_DEVICE.status with datatype=BOOLEAN,encoding=PLAIN") | - -### 5.5 数据表接口 - -| api name | parameters | notes | use example | -| -------------------------- | ------------------------------------------------------------ | --------------------------- | ------------------------------------------------------------ | -| SetStorageGroup | string | set storage group | session_pool.SetStorageGroup("root.97209_TEST_CSHARP_CLIENT_GROUP_01") | -| CreateTimeSeries | string, TSDataType, TSEncoding, Compressor | create time series | session_pool.InsertTabletsAsync(tablets) | -| DeleteStorageGroupAsync | string | delete single storage group | session_pool.DeleteStorageGroupAsync("root.97209_TEST_CSHARP_CLIENT_GROUP_01") | -| DeleteStorageGroupsAsync | List\ | delete storage group | session_pool.DeleteStorageGroupAsync("root.97209_TEST_CSHARP_CLIENT_GROUP") | -| CreateMultiTimeSeriesAsync | List\, List\ , List\ , List\ | create multi time series | session_pool.CreateMultiTimeSeriesAsync(ts_path_lst, data_type_lst, encoding_lst, compressor_lst); | -| DeleteTimeSeriesAsync | List\ | delete time series | | -| DeleteTimeSeriesAsync | string | delete time series | | -| DeleteDataAsync | List\, long, long | delete data | session_pool.DeleteDataAsync(ts_path_lst, 2, 3) | - -### 5.6 **辅助接口** - -| api name | parameters | notes | use example | -| -------------------------- | ---------- | --------------------------- | ---------------------------------------------------- | -| CheckTimeSeriesExistsAsync | string | check if time series exists | session_pool.CheckTimeSeriesExistsAsync(time series) | - - - -用法可以参考[用户示例](https://github.com/apache/iotdb-client-csharp/tree/main/samples/Apache.IoTDB.Samples) - -## 6. 连接池 - -为了实现并发客户端请求,我们提供了针对原生接口的连接池(`SessionPool`),由于`SessionPool`本身为`Session`的超集,当`SessionPool`的`pool_size`参数设置为1时,退化为原来的`Session` - -我们使用`ConcurrentQueue`数据结构封装了一个客户端队列,以维护与服务端的多个连接,当调用`Open()`接口时,会在该队列中创建指定个数的客户端,同时通过`System.Threading.Monitor`类实现对队列的同步访问。 - -当请求发生时,会尝试从连接池中寻找一个空闲的客户端连接,如果没有空闲连接,那么程序将需要等待直到有空闲连接 - -当一个连接被用完后,他会自动返回池中等待下次被使用 - -## 7. ByteBuffer - -在传入RPC接口参数时,需要对Record和Tablet两种数据结构进行序列化,我们主要通过封装的ByteBuffer类实现 - -在封装字节序列的基础上,我们进行了内存预申请与内存倍增的优化,减少了序列化过程中内存的申请和释放,在一个拥有20000行的Tablet上进行序列化测试时,速度比起原生的数组动态增长具有**35倍的性能加速** - -### 7.1 实现介绍 -在进行`RowRecords`以及`Tablet`的插入时,我们需要对多行RowRecord和Tablet进行序列化以进行发送。客户端中的序列化实现主要依赖于ByteBuffer完成。接下来我们介绍ByteBuffer的实现细节。本文包含如下几点内容: - - 序列化的协议 - - C#与Java的大小端的差异 - - ByteBuffer内存倍增算法 - -### 7.2 序列化协议 -客户端向IoTDB服务器发送的序列化数据总体应该包含两个信息。 - - 数据类型 - - 数据本身 - -其中对于`字符串`的序列化时,我们需要再加入字符串的长度信息。即一个字符串的序列化完整结果为: +#### 4.3.1 Record - [类型][长度][数据内容] -接下来我们分别介绍`RowRecord`、`Tablet`的序列化方式 +| 方法名 | 参数 | 描述 | 示例 | +| ------------------------------------- | ------------------------------- | ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------- | +| InsertRecordAsync | string, RowRecord | 插入单条记录 | session\_pool.InsertRecordAsync("root.97209\_TEST\_CSHARP\_CLIENT\_GROUP.TEST\_CSHARP\_CLIENT\_DEVICE", new RowRecord(1, values, measures)); | +| InsertRecordsAsync | List, List | 插入多条记录 | session\_pool.InsertRecordsAsync(device\_id, rowRecords) | +| InsertRecordsOfOneDeviceAsync | string, List | 插入同一设备的记录 | session\_pool.InsertRecordsOfOneDeviceAsync(device\_id, rowRecords) | +| InsertRecordsOfOneDeviceSortedAsync | string, List | 插入同一设备的有序记录 | session\_pool.InsertRecordsOfOneDeviceSortedAsync(deviceId, sortedRowRecords); | +| TestInsertRecordAsync | string, RowRecord | 测试插入记录 | session\_pool.TestInsertRecordAsync("root.97209\_TEST\_CSHARP\_CLIENT\_GROUP.TEST\_CSHARP\_CLIENT\_DEVICE", rowRecord) | +| TestInsertRecordsAsync | List, List | 测试插入记录 | session\_pool.TestInsertRecordsAsync(device\_id, rowRecords) | -#### RowRecord -我们对RowRecord进行序列化时,`伪代码`如下: -```csharp -public byte[] value_to_bytes(List data_types, List values){ - ByteBuffer buffer = new ByteBuffer(values.Count); - for(int i = 0;i < data_types.Count(); i++){ - buffer.add_type((data_types[i]); - buffer.add_val(values[i]); - } -} -``` +#### 4.3.2 Tablet -对于其序列化的结果格式如下: +| 方法名 | 参数 | 描述 | 示例 | +| ------------------------ | -------------- | ------------------ | ----------------------------------------------- | +| InsertTabletAsync | Tablet | 插入单个 tablet | session\_pool.InsertTabletAsync(tablet) | +| InsertTabletsAsync | List | 插入一批 tablets | session\_pool.InsertTabletsAsync(tablets) | +| TestInsertTabletAsync | Tablet | 测试插入 tablet | session\_pool.TestInsertTabletAsync(tablet) | +| TestInsertTabletsAsync | List | 测试插入 tablets | session\_pool.TestInsertTabletsAsync(tablets) | - [数据类型1][数据1][数据类型2][数据2]...[数据类型N][数据N] - 其中数据类型为自定义的`Enum`变量,分别如下: -```csharp -public enum TSDataType{BOOLEAN, INT32, INT64, FLOAT, DOUBLE, TEXT, NONE}; -``` +### 4.4 查询接口 -#### Tablet序列化 -使用`Tabelt`进行数据插入时有如下限制: - - 限制:Tablet中数据不能有空值 -由于向 `IoTDB`服务器发送`Tablet`数据插入请求时会携带`行数`, `列数`, `列数据类型`,所以`Tabelt`序列化时我们不需要加入数据类型信息。`Tablet`是`按照列进行序列化`,这是因为后端可以通过行数得知出当前列的元素个数,同时根据列类型来对数据进行解析。 - -### 7.3 CSharp与Java序列化数据时的大小端差异 -由于Java序列化默认大端协议,而CSharp序列化默认得到小端序列。所以我们在CSharp中序列化数据之后,需要对数据进行反转这样后端才可以正常解析。同时当我们从后端获取到序列化的结果时(如`SessionDataset`),我们也需要对获得的数据进行反转以解析内容。这其中特例便是字符串的序列化,CSharp中对字符串的序列化结果为大端序,所以序列化字符串或者接收到字符串序列化结果时,不需要反转序列结果。 - -### 7.4 ByteBuffer内存倍增法 -拥有数万行的Tablet的序列化结果可能有上百兆,为了能够高效的实现大`Tablet`的序列化,我们对ByteBuffer使用`内存倍增法`的策略来减少序列化过程中对于内存的申请和释放。即当当前的buffer的长度不足以放下序列化结果时,我们将当前buffer的内存`至少`扩增2倍。这极大的减少了内存的申请释放次数,加速了大Tablet的序列化速度。 -```csharp -private void extend_buffer(int space_need){ - if(write_pos + space_need >= total_length){ - total_length = max(space_need, total_length); - byte[] new_buffer = new byte[total_length * 2]; - buffer.CopyTo(new_buffer, 0); - buffer = new_buffer; - total_length = 2 * total_length; - } -} -``` -同时在序列化`Tablet`时,我们首先根据Tablet的`行数`,`列数`以及每一列的数据类型估计当前`Tablet`序列化结果所需要的内存大小,并在初始化时进行内存的申请。这进一步的减少了内存的申请释放频率。 +| 方法名 | 参数 | 描述 | 示例 | +| -------------------------------- | -------- | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| ExecuteQueryStatementAsync | string | 执行 SQL 查询语句 | session\_pool.ExecuteQueryStatementAsync("select \* from root.97209\_TEST\_CSHARP\_CLIENT\_GROUP.TEST\_CSHARP\_CLIENT\_DEVICE where time<15"); | +| ExecuteNonQueryStatementAsync| string | 执行 SQL 非查询语句 | session\_pool.ExecuteNonQueryStatementAsync( "create timeseries root.97209\_TEST\_CSHARP\_CLIENT\_GROUP.TEST\_CSHARP\_CLIENT\_DEVICE.status with datatype=BOOLEAN,encoding=PLAIN") | -通过上述的策略,我们在一个有`20000`行的Tablet上进行测试时,序列化速度相比Naive数组长度动态生长实现算法具有约35倍的性能加速。 +### 4.5 删除接口 -## 8. 异常重连 +| 方法名 | 参数 | 描述 | 示例 | +| -------------------------- | -------------------------- | ---------------- | -------------------------------------------------------------------------------------- | +| DeleteStorageGroupAsync | string | 删除单个存储组 | session\_pool.DeleteStorageGroupAsync("root.97209\_TEST\_CSHARP\_CLIENT\_GROUP\_01") | +| DeleteStorageGroupsAsync | List | 删除存储组 | session\_pool.DeleteStorageGroupAsync("root.97209\_TEST\_CSHARP\_CLIENT\_GROUP") | +| DeleteTimeSeriesAsync | List | 删除时间序列 | session\_pool.DeleteTimeSeriesAsync(ts\_path\_lst) | +| DeleteTimeSeriesAsync | string | 删除时间序列 | session\_pool.DeleteTimeSeriesAsync(ts\_path) | +| DeleteDataAsync | List, long, long | 删除数据 | session\_pool.DeleteDataAsync(ts\_path\_lst, 2, 3) | -当服务端发生异常或者宕机重启时,客户端中原来通过`Open()`产生的的session会失效,抛出`TException`异常 +## 5. 示例代码 -为了避免这一情况的发生,我们对大部分的接口进行了增强,一旦出现连接问题,就会尝试重新调用`Open()`接口并创建新的Session,并尝试重新发送对应的请求 +完整示例请参考:[Apache.IoTDB.Samples](https://github.com/apache/iotdb-client-csharp/tree/main/samples/Apache.IoTDB.Samples) diff --git a/src/zh/UserGuide/V1.3.x/API/Programming-CSharp-Native-API.md b/src/zh/UserGuide/V1.3.x/API/Programming-CSharp-Native-API.md index 9f1e2f582..9a393516b 100644 --- a/src/zh/UserGuide/V1.3.x/API/Programming-CSharp-Native-API.md +++ b/src/zh/UserGuide/V1.3.x/API/Programming-CSharp-Native-API.md @@ -21,34 +21,32 @@ # C# 原生接口 -## 依赖 +## 环境要求 -- .NET SDK >= 5.0 或 .NET Framework 4.x -- Thrift >= 0.14.1 -- NLog >= 4.7.9 +* .NET SDK >= 5.0 或 .NET Framework 4.x +* Thrift >= 0.14.1 +* NLog >= 4.7.9 -## 安装 +## 依赖安装 您可以使用 NuGet Package Manager, .NET CLI等工具来安装,以 .NET CLI为例 -如果您使用的是\.NET 5.0 或者更高版本的SDK,输入如下命令即可安装最新的NuGet包 +如果您使用的是.NET 5.0 或者更高版本的SDK,输入如下命令即可安装最新的NuGet包 -``` +```Bash dotnet add package Apache.IoTDB ``` 如果您想安装更早版本的客户端,只需要指定版本即可 -```bash +```Bash # 安装0.12.1.2版本的客户端 dotnet add package Apache.IoTDB --version 0.12.1.2 ``` -## 基本接口说明 - -Session接口在语义上和其他语言客户端相同 +## 快速入门 -```csharp +```C# // 参数定义 string host = "localhost"; int port = 6667; @@ -82,187 +80,87 @@ await session_pool.InsertTabletAsync(tablet); await session_pool.Close(); ``` -## **Row Record** +## 全量接口说明 -- 对**IoTDB**中的`record`数据进行封装和抽象。 -- 示例: +SessionPool 连接池支持并发客户端请求,线程安全。当 `pool_size`设为 1 时,其行为等同于单个 session。推荐使用 SessionPool ,作为实现与数据库交互的核心接口,SessionPool 集成了丰富的方法,支持数据写入、查询以及元数据操作等功能,详细介绍见下文。 - | timestamp | status | temperature | - | --------- | ------ | ----------- | - | 1 | 0 | 20 | +### 基础接口 -- 构造方法: +| 方法名 | 参数 | 描述 | 示例 | +| ---------------- | --------------------------- | -------------- | -------------------------------- | +| Open | bool | 打开会话 | session\_pool.Open(false) | +| Close | null | 关闭会话 | session\_pool.Close() | +| IsOpen | null | 查看会话状态 | session\_pool.IsOpen() | +| OpenDebugMode | LoggingConfiguration=null | 启用调试模式 | session\_pool.OpenDebugMode() | +| CloseDebugMode | null | 禁用调试模式 | session\_pool.CloseDebugMode() | +| SetTimeZone | string | 设置时区 | session\_pool.GetTimeZone() | +| GetTimeZone | null | 获取时区 | session\_pool.GetTimeZone() | -```csharp -var rowRecord = - new RowRecord(long timestamps, List values, List measurements); -``` +### 元数据接口 -### **Tablet** +| 方法名 | 参数 | 描述 | 示例 | +| ---------------------------- | ---------------------------------------------------------------------- | ---------------------- | ----------------------------------------------------------------------------------------------------------- | +| SetStorageGroup | string | (创建)存储组 | session\_pool.SetStorageGroup("root.97209\_TEST\_CSHARP\_CLIENT\_GROUP\_01") | +| CreateTimeSeries | string, TSDataType, TSEncoding, Compressor | 创建时间序列 | session\_pool.InsertTabletsAsync(tablets) | +| CreateMultiTimeSeriesAsync | List, List , List , List | 创建多个时间序列 | session\_pool.CreateMultiTimeSeriesAsync(ts\_path\_lst, data\_type\_lst, encoding\_lst, compressor\_lst); | +| CheckTimeSeriesExistsAsync | string | 查看时间序列是否存在 | session\_pool.CheckTimeSeriesExistsAsync(time series) | -- 一种类似于表格的数据结构,包含一个设备的若干行非空数据块。 -- 示例: +### 写入接口 - | time | status | temperature | - | ---- | ------ | ----------- | - | 1 | 0 | 20 | - | 2 | 0 | 20 | - | 3 | 3 | 21 | +C# 原生接口支持通过 Record 和 Tablet 两种方式进行数据写入: -- 构造方法: +* RowRecord 是对 IoTDB 中的`record`数据进行封装和抽象,适合单行数据写入的场景,其构造方法如下 -```csharp -var tablet = - Tablet(string deviceId, List measurements, List> values, List timestamps); +```C# +var rowRecord = + new RowRecord(long timestamps, List values, List measurements); ``` +* Tablet 是一种类似于表格的数据结构,适合一个设备若干行非空数据块写入的场景,其构造方法如下 +```C# +var tablet = + new Tablet(string deviceId, List measurements, List> values, List timestamps); +``` -## **API** - -### **基础接口** - -| api name | parameters | notes | use example | -| -------------- | ------------------------- | ------------------------ | ----------------------------- | -| Open | bool | open session | session_pool.Open(false) | -| Close | null | close session | session_pool.Close() | -| IsOpen | null | check if session is open | session_pool.IsOpen() | -| OpenDebugMode | LoggingConfiguration=null | open debug mode | session_pool.OpenDebugMode() | -| CloseDebugMode | null | close debug mode | session_pool.CloseDebugMode() | -| SetTimeZone | string | set time zone | session_pool.GetTimeZone() | -| GetTimeZone | null | get time zone | session_pool.GetTimeZone() | - -### **Record相关接口** - -| api name | parameters | notes | use example | -| ----------------------------------- | ----------------------------- | ----------------------------------- | ------------------------------------------------------------ | -| InsertRecordAsync | string, RowRecord | insert single record | session_pool.InsertRecordAsync("root.97209_TEST_CSHARP_CLIENT_GROUP.TEST_CSHARP_CLIENT_DEVICE", new RowRecord(1, values, measures)); | -| InsertRecordsAsync | List\, List\ | insert records | session_pool.InsertRecordsAsync(device_id, rowRecords) | -| InsertRecordsOfOneDeviceAsync | string, List\ | insert records of one device | session_pool.InsertRecordsOfOneDeviceAsync(device_id, rowRecords) | -| InsertRecordsOfOneDeviceSortedAsync | string, List\ | insert sorted records of one device | InsertRecordsOfOneDeviceSortedAsync(deviceId, sortedRowRecords); | -| TestInsertRecordAsync | string, RowRecord | test insert record | session_pool.TestInsertRecordAsync("root.97209_TEST_CSHARP_CLIENT_GROUP.TEST_CSHARP_CLIENT_DEVICE", rowRecord) | -| TestInsertRecordsAsync | List\, List\ | test insert record | session_pool.TestInsertRecordsAsync(device_id, rowRecords) | - -### **Tablet相关接口** - -| api name | parameters | notes | use example | -| ---------------------- | ------------ | -------------------- | -------------------------------------------- | -| InsertTabletAsync | Tablet | insert single tablet | session_pool.InsertTabletAsync(tablet) | -| InsertTabletsAsync | List\ | insert tablets | session_pool.InsertTabletsAsync(tablets) | -| TestInsertTabletAsync | Tablet | test insert tablet | session_pool.TestInsertTabletAsync(tablet) | -| TestInsertTabletsAsync | List\ | test insert tablets | session_pool.TestInsertTabletsAsync(tablets) | - -### **SQL语句接口** - -| api name | parameters | notes | use example | -| ----------------------------- | ---------- | ------------------------------ | ------------------------------------------------------------ | -| ExecuteQueryStatementAsync | string | execute sql query statement | session_pool.ExecuteQueryStatementAsync("select * from root.97209_TEST_CSHARP_CLIENT_GROUP.TEST_CSHARP_CLIENT_DEVICE where time<15"); | -| ExecuteNonQueryStatementAsync | string | execute sql nonquery statement | session_pool.ExecuteNonQueryStatementAsync( "create timeseries root.97209_TEST_CSHARP_CLIENT_GROUP.TEST_CSHARP_CLIENT_DEVICE.status with datatype=BOOLEAN,encoding=PLAIN") | - -### 数据表接口 - -| api name | parameters | notes | use example | -| -------------------------- | ------------------------------------------------------------ | --------------------------- | ------------------------------------------------------------ | -| SetStorageGroup | string | set storage group | session_pool.SetStorageGroup("root.97209_TEST_CSHARP_CLIENT_GROUP_01") | -| CreateTimeSeries | string, TSDataType, TSEncoding, Compressor | create time series | session_pool.InsertTabletsAsync(tablets) | -| DeleteStorageGroupAsync | string | delete single storage group | session_pool.DeleteStorageGroupAsync("root.97209_TEST_CSHARP_CLIENT_GROUP_01") | -| DeleteStorageGroupsAsync | List\ | delete storage group | session_pool.DeleteStorageGroupAsync("root.97209_TEST_CSHARP_CLIENT_GROUP") | -| CreateMultiTimeSeriesAsync | List\, List\ , List\ , List\ | create multi time series | session_pool.CreateMultiTimeSeriesAsync(ts_path_lst, data_type_lst, encoding_lst, compressor_lst); | -| DeleteTimeSeriesAsync | List\ | delete time series | | -| DeleteTimeSeriesAsync | string | delete time series | | -| DeleteDataAsync | List\, long, long | delete data | session_pool.DeleteDataAsync(ts_path_lst, 2, 3) | - -### **辅助接口** - -| api name | parameters | notes | use example | -| -------------------------- | ---------- | --------------------------- | ---------------------------------------------------- | -| CheckTimeSeriesExistsAsync | string | check if time series exists | session_pool.CheckTimeSeriesExistsAsync(time series) | - - - -用法可以参考[用户示例](https://github.com/apache/iotdb-client-csharp/tree/main/samples/Apache.IoTDB.Samples) - -## 连接池 - -为了实现并发客户端请求,我们提供了针对原生接口的连接池(`SessionPool`),由于`SessionPool`本身为`Session`的超集,当`SessionPool`的`pool_size`参数设置为1时,退化为原来的`Session` - -我们使用`ConcurrentQueue`数据结构封装了一个客户端队列,以维护与服务端的多个连接,当调用`Open()`接口时,会在该队列中创建指定个数的客户端,同时通过`System.Threading.Monitor`类实现对队列的同步访问。 - -当请求发生时,会尝试从连接池中寻找一个空闲的客户端连接,如果没有空闲连接,那么程序将需要等待直到有空闲连接 - -当一个连接被用完后,他会自动返回池中等待下次被使用 - -## ByteBuffer - -在传入RPC接口参数时,需要对Record和Tablet两种数据结构进行序列化,我们主要通过封装的ByteBuffer类实现 - -在封装字节序列的基础上,我们进行了内存预申请与内存倍增的优化,减少了序列化过程中内存的申请和释放,在一个拥有20000行的Tablet上进行序列化测试时,速度比起原生的数组动态增长具有**35倍的性能加速** - -### 实现介绍 -在进行`RowRecords`以及`Tablet`的插入时,我们需要对多行RowRecord和Tablet进行序列化以进行发送。客户端中的序列化实现主要依赖于ByteBuffer完成。接下来我们介绍ByteBuffer的实现细节。本文包含如下几点内容: - - 序列化的协议 - - C#与Java的大小端的差异 - - ByteBuffer内存倍增算法 - -### 序列化协议 -客户端向IoTDB服务器发送的序列化数据总体应该包含两个信息。 - - 数据类型 - - 数据本身 - -其中对于`字符串`的序列化时,我们需要再加入字符串的长度信息。即一个字符串的序列化完整结果为: +#### Record - [类型][长度][数据内容] -接下来我们分别介绍`RowRecord`、`Tablet`的序列化方式 +| 方法名 | 参数 | 描述 | 示例 | +| ------------------------------------- | ------------------------------- | ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------- | +| InsertRecordAsync | string, RowRecord | 插入单条记录 | session\_pool.InsertRecordAsync("root.97209\_TEST\_CSHARP\_CLIENT\_GROUP.TEST\_CSHARP\_CLIENT\_DEVICE", new RowRecord(1, values, measures)); | +| InsertRecordsAsync | List, List | 插入多条记录 | session\_pool.InsertRecordsAsync(device\_id, rowRecords) | +| InsertRecordsOfOneDeviceAsync | string, List | 插入同一设备的记录 | session\_pool.InsertRecordsOfOneDeviceAsync(device\_id, rowRecords) | +| InsertRecordsOfOneDeviceSortedAsync | string, List | 插入同一设备的有序记录 | session\_pool.InsertRecordsOfOneDeviceSortedAsync(deviceId, sortedRowRecords); | +| TestInsertRecordAsync | string, RowRecord | 测试插入记录 | session\_pool.TestInsertRecordAsync("root.97209\_TEST\_CSHARP\_CLIENT\_GROUP.TEST\_CSHARP\_CLIENT\_DEVICE", rowRecord) | +| TestInsertRecordsAsync | List, List | 测试插入记录 | session\_pool.TestInsertRecordsAsync(device\_id, rowRecords) | -#### RowRecord -我们对RowRecord进行序列化时,`伪代码`如下: -```csharp -public byte[] value_to_bytes(List data_types, List values){ - ByteBuffer buffer = new ByteBuffer(values.Count); - for(int i = 0;i < data_types.Count(); i++){ - buffer.add_type((data_types[i]); - buffer.add_val(values[i]); - } -} -``` +#### Tablet -对于其序列化的结果格式如下: +| 方法名 | 参数 | 描述 | 示例 | +| ------------------------ | -------------- | ------------------ | ----------------------------------------------- | +| InsertTabletAsync | Tablet | 插入单个 tablet | session\_pool.InsertTabletAsync(tablet) | +| InsertTabletsAsync | List | 插入一批 tablets | session\_pool.InsertTabletsAsync(tablets) | +| TestInsertTabletAsync | Tablet | 测试插入 tablet | session\_pool.TestInsertTabletAsync(tablet) | +| TestInsertTabletsAsync | List | 测试插入 tablets | session\_pool.TestInsertTabletsAsync(tablets) | - [数据类型1][数据1][数据类型2][数据2]...[数据类型N][数据N] - 其中数据类型为自定义的`Enum`变量,分别如下: -```csharp -public enum TSDataType{BOOLEAN, INT32, INT64, FLOAT, DOUBLE, TEXT, NONE}; -``` +### 查询接口 -#### Tablet序列化 -使用`Tabelt`进行数据插入时有如下限制: - - 限制:Tablet中数据不能有空值 -由于向 `IoTDB`服务器发送`Tablet`数据插入请求时会携带`行数`, `列数`, `列数据类型`,所以`Tabelt`序列化时我们不需要加入数据类型信息。`Tablet`是`按照列进行序列化`,这是因为后端可以通过行数得知出当前列的元素个数,同时根据列类型来对数据进行解析。 - -### CSharp与Java序列化数据时的大小端差异 -由于Java序列化默认大端协议,而CSharp序列化默认得到小端序列。所以我们在CSharp中序列化数据之后,需要对数据进行反转这样后端才可以正常解析。同时当我们从后端获取到序列化的结果时(如`SessionDataset`),我们也需要对获得的数据进行反转以解析内容。这其中特例便是字符串的序列化,CSharp中对字符串的序列化结果为大端序,所以序列化字符串或者接收到字符串序列化结果时,不需要反转序列结果。 - -### ByteBuffer内存倍增法 -拥有数万行的Tablet的序列化结果可能有上百兆,为了能够高效的实现大`Tablet`的序列化,我们对ByteBuffer使用`内存倍增法`的策略来减少序列化过程中对于内存的申请和释放。即当当前的buffer的长度不足以放下序列化结果时,我们将当前buffer的内存`至少`扩增2倍。这极大的减少了内存的申请释放次数,加速了大Tablet的序列化速度。 -```csharp -private void extend_buffer(int space_need){ - if(write_pos + space_need >= total_length){ - total_length = max(space_need, total_length); - byte[] new_buffer = new byte[total_length * 2]; - buffer.CopyTo(new_buffer, 0); - buffer = new_buffer; - total_length = 2 * total_length; - } -} -``` -同时在序列化`Tablet`时,我们首先根据Tablet的`行数`,`列数`以及每一列的数据类型估计当前`Tablet`序列化结果所需要的内存大小,并在初始化时进行内存的申请。这进一步的减少了内存的申请释放频率。 +| 方法名 | 参数 | 描述 | 示例 | +| -------------------------------- | -------- | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| ExecuteQueryStatementAsync | string | 执行 SQL 查询语句 | session\_pool.ExecuteQueryStatementAsync("select \* from root.97209\_TEST\_CSHARP\_CLIENT\_GROUP.TEST\_CSHARP\_CLIENT\_DEVICE where time<15"); | +| ExecuteNonQueryStatementAsync| string | 执行 SQL 非查询语句 | session\_pool.ExecuteNonQueryStatementAsync( "create timeseries root.97209\_TEST\_CSHARP\_CLIENT\_GROUP.TEST\_CSHARP\_CLIENT\_DEVICE.status with datatype=BOOLEAN,encoding=PLAIN") | -通过上述的策略,我们在一个有`20000`行的Tablet上进行测试时,序列化速度相比Naive数组长度动态生长实现算法具有约35倍的性能加速。 +### 删除接口 -## 异常重连 +| 方法名 | 参数 | 描述 | 示例 | +| -------------------------- | -------------------------- | ---------------- | -------------------------------------------------------------------------------------- | +| DeleteStorageGroupAsync | string | 删除单个存储组 | session\_pool.DeleteStorageGroupAsync("root.97209\_TEST\_CSHARP\_CLIENT\_GROUP\_01") | +| DeleteStorageGroupsAsync | List | 删除存储组 | session\_pool.DeleteStorageGroupAsync("root.97209\_TEST\_CSHARP\_CLIENT\_GROUP") | +| DeleteTimeSeriesAsync | List | 删除时间序列 | session\_pool.DeleteTimeSeriesAsync(ts\_path\_lst) | +| DeleteTimeSeriesAsync | string | 删除时间序列 | session\_pool.DeleteTimeSeriesAsync(ts\_path) | +| DeleteDataAsync | List, long, long | 删除数据 | session\_pool.DeleteDataAsync(ts\_path\_lst, 2, 3) | -当服务端发生异常或者宕机重启时,客户端中原来通过`Open()`产生的的session会失效,抛出`TException`异常 +## 示例代码 -为了避免这一情况的发生,我们对大部分的接口进行了增强,一旦出现连接问题,就会尝试重新调用`Open()`接口并创建新的Session,并尝试重新发送对应的请求 +完整示例请参考:[Apache.IoTDB.Samples](https://github.com/apache/iotdb-client-csharp/tree/main/samples/Apache.IoTDB.Samples) diff --git a/src/zh/UserGuide/dev-1.3/API/Programming-CSharp-Native-API.md b/src/zh/UserGuide/dev-1.3/API/Programming-CSharp-Native-API.md index 9f1e2f582..9a393516b 100644 --- a/src/zh/UserGuide/dev-1.3/API/Programming-CSharp-Native-API.md +++ b/src/zh/UserGuide/dev-1.3/API/Programming-CSharp-Native-API.md @@ -21,34 +21,32 @@ # C# 原生接口 -## 依赖 +## 环境要求 -- .NET SDK >= 5.0 或 .NET Framework 4.x -- Thrift >= 0.14.1 -- NLog >= 4.7.9 +* .NET SDK >= 5.0 或 .NET Framework 4.x +* Thrift >= 0.14.1 +* NLog >= 4.7.9 -## 安装 +## 依赖安装 您可以使用 NuGet Package Manager, .NET CLI等工具来安装,以 .NET CLI为例 -如果您使用的是\.NET 5.0 或者更高版本的SDK,输入如下命令即可安装最新的NuGet包 +如果您使用的是.NET 5.0 或者更高版本的SDK,输入如下命令即可安装最新的NuGet包 -``` +```Bash dotnet add package Apache.IoTDB ``` 如果您想安装更早版本的客户端,只需要指定版本即可 -```bash +```Bash # 安装0.12.1.2版本的客户端 dotnet add package Apache.IoTDB --version 0.12.1.2 ``` -## 基本接口说明 - -Session接口在语义上和其他语言客户端相同 +## 快速入门 -```csharp +```C# // 参数定义 string host = "localhost"; int port = 6667; @@ -82,187 +80,87 @@ await session_pool.InsertTabletAsync(tablet); await session_pool.Close(); ``` -## **Row Record** +## 全量接口说明 -- 对**IoTDB**中的`record`数据进行封装和抽象。 -- 示例: +SessionPool 连接池支持并发客户端请求,线程安全。当 `pool_size`设为 1 时,其行为等同于单个 session。推荐使用 SessionPool ,作为实现与数据库交互的核心接口,SessionPool 集成了丰富的方法,支持数据写入、查询以及元数据操作等功能,详细介绍见下文。 - | timestamp | status | temperature | - | --------- | ------ | ----------- | - | 1 | 0 | 20 | +### 基础接口 -- 构造方法: +| 方法名 | 参数 | 描述 | 示例 | +| ---------------- | --------------------------- | -------------- | -------------------------------- | +| Open | bool | 打开会话 | session\_pool.Open(false) | +| Close | null | 关闭会话 | session\_pool.Close() | +| IsOpen | null | 查看会话状态 | session\_pool.IsOpen() | +| OpenDebugMode | LoggingConfiguration=null | 启用调试模式 | session\_pool.OpenDebugMode() | +| CloseDebugMode | null | 禁用调试模式 | session\_pool.CloseDebugMode() | +| SetTimeZone | string | 设置时区 | session\_pool.GetTimeZone() | +| GetTimeZone | null | 获取时区 | session\_pool.GetTimeZone() | -```csharp -var rowRecord = - new RowRecord(long timestamps, List values, List measurements); -``` +### 元数据接口 -### **Tablet** +| 方法名 | 参数 | 描述 | 示例 | +| ---------------------------- | ---------------------------------------------------------------------- | ---------------------- | ----------------------------------------------------------------------------------------------------------- | +| SetStorageGroup | string | (创建)存储组 | session\_pool.SetStorageGroup("root.97209\_TEST\_CSHARP\_CLIENT\_GROUP\_01") | +| CreateTimeSeries | string, TSDataType, TSEncoding, Compressor | 创建时间序列 | session\_pool.InsertTabletsAsync(tablets) | +| CreateMultiTimeSeriesAsync | List, List , List , List | 创建多个时间序列 | session\_pool.CreateMultiTimeSeriesAsync(ts\_path\_lst, data\_type\_lst, encoding\_lst, compressor\_lst); | +| CheckTimeSeriesExistsAsync | string | 查看时间序列是否存在 | session\_pool.CheckTimeSeriesExistsAsync(time series) | -- 一种类似于表格的数据结构,包含一个设备的若干行非空数据块。 -- 示例: +### 写入接口 - | time | status | temperature | - | ---- | ------ | ----------- | - | 1 | 0 | 20 | - | 2 | 0 | 20 | - | 3 | 3 | 21 | +C# 原生接口支持通过 Record 和 Tablet 两种方式进行数据写入: -- 构造方法: +* RowRecord 是对 IoTDB 中的`record`数据进行封装和抽象,适合单行数据写入的场景,其构造方法如下 -```csharp -var tablet = - Tablet(string deviceId, List measurements, List> values, List timestamps); +```C# +var rowRecord = + new RowRecord(long timestamps, List values, List measurements); ``` +* Tablet 是一种类似于表格的数据结构,适合一个设备若干行非空数据块写入的场景,其构造方法如下 +```C# +var tablet = + new Tablet(string deviceId, List measurements, List> values, List timestamps); +``` -## **API** - -### **基础接口** - -| api name | parameters | notes | use example | -| -------------- | ------------------------- | ------------------------ | ----------------------------- | -| Open | bool | open session | session_pool.Open(false) | -| Close | null | close session | session_pool.Close() | -| IsOpen | null | check if session is open | session_pool.IsOpen() | -| OpenDebugMode | LoggingConfiguration=null | open debug mode | session_pool.OpenDebugMode() | -| CloseDebugMode | null | close debug mode | session_pool.CloseDebugMode() | -| SetTimeZone | string | set time zone | session_pool.GetTimeZone() | -| GetTimeZone | null | get time zone | session_pool.GetTimeZone() | - -### **Record相关接口** - -| api name | parameters | notes | use example | -| ----------------------------------- | ----------------------------- | ----------------------------------- | ------------------------------------------------------------ | -| InsertRecordAsync | string, RowRecord | insert single record | session_pool.InsertRecordAsync("root.97209_TEST_CSHARP_CLIENT_GROUP.TEST_CSHARP_CLIENT_DEVICE", new RowRecord(1, values, measures)); | -| InsertRecordsAsync | List\, List\ | insert records | session_pool.InsertRecordsAsync(device_id, rowRecords) | -| InsertRecordsOfOneDeviceAsync | string, List\ | insert records of one device | session_pool.InsertRecordsOfOneDeviceAsync(device_id, rowRecords) | -| InsertRecordsOfOneDeviceSortedAsync | string, List\ | insert sorted records of one device | InsertRecordsOfOneDeviceSortedAsync(deviceId, sortedRowRecords); | -| TestInsertRecordAsync | string, RowRecord | test insert record | session_pool.TestInsertRecordAsync("root.97209_TEST_CSHARP_CLIENT_GROUP.TEST_CSHARP_CLIENT_DEVICE", rowRecord) | -| TestInsertRecordsAsync | List\, List\ | test insert record | session_pool.TestInsertRecordsAsync(device_id, rowRecords) | - -### **Tablet相关接口** - -| api name | parameters | notes | use example | -| ---------------------- | ------------ | -------------------- | -------------------------------------------- | -| InsertTabletAsync | Tablet | insert single tablet | session_pool.InsertTabletAsync(tablet) | -| InsertTabletsAsync | List\ | insert tablets | session_pool.InsertTabletsAsync(tablets) | -| TestInsertTabletAsync | Tablet | test insert tablet | session_pool.TestInsertTabletAsync(tablet) | -| TestInsertTabletsAsync | List\ | test insert tablets | session_pool.TestInsertTabletsAsync(tablets) | - -### **SQL语句接口** - -| api name | parameters | notes | use example | -| ----------------------------- | ---------- | ------------------------------ | ------------------------------------------------------------ | -| ExecuteQueryStatementAsync | string | execute sql query statement | session_pool.ExecuteQueryStatementAsync("select * from root.97209_TEST_CSHARP_CLIENT_GROUP.TEST_CSHARP_CLIENT_DEVICE where time<15"); | -| ExecuteNonQueryStatementAsync | string | execute sql nonquery statement | session_pool.ExecuteNonQueryStatementAsync( "create timeseries root.97209_TEST_CSHARP_CLIENT_GROUP.TEST_CSHARP_CLIENT_DEVICE.status with datatype=BOOLEAN,encoding=PLAIN") | - -### 数据表接口 - -| api name | parameters | notes | use example | -| -------------------------- | ------------------------------------------------------------ | --------------------------- | ------------------------------------------------------------ | -| SetStorageGroup | string | set storage group | session_pool.SetStorageGroup("root.97209_TEST_CSHARP_CLIENT_GROUP_01") | -| CreateTimeSeries | string, TSDataType, TSEncoding, Compressor | create time series | session_pool.InsertTabletsAsync(tablets) | -| DeleteStorageGroupAsync | string | delete single storage group | session_pool.DeleteStorageGroupAsync("root.97209_TEST_CSHARP_CLIENT_GROUP_01") | -| DeleteStorageGroupsAsync | List\ | delete storage group | session_pool.DeleteStorageGroupAsync("root.97209_TEST_CSHARP_CLIENT_GROUP") | -| CreateMultiTimeSeriesAsync | List\, List\ , List\ , List\ | create multi time series | session_pool.CreateMultiTimeSeriesAsync(ts_path_lst, data_type_lst, encoding_lst, compressor_lst); | -| DeleteTimeSeriesAsync | List\ | delete time series | | -| DeleteTimeSeriesAsync | string | delete time series | | -| DeleteDataAsync | List\, long, long | delete data | session_pool.DeleteDataAsync(ts_path_lst, 2, 3) | - -### **辅助接口** - -| api name | parameters | notes | use example | -| -------------------------- | ---------- | --------------------------- | ---------------------------------------------------- | -| CheckTimeSeriesExistsAsync | string | check if time series exists | session_pool.CheckTimeSeriesExistsAsync(time series) | - - - -用法可以参考[用户示例](https://github.com/apache/iotdb-client-csharp/tree/main/samples/Apache.IoTDB.Samples) - -## 连接池 - -为了实现并发客户端请求,我们提供了针对原生接口的连接池(`SessionPool`),由于`SessionPool`本身为`Session`的超集,当`SessionPool`的`pool_size`参数设置为1时,退化为原来的`Session` - -我们使用`ConcurrentQueue`数据结构封装了一个客户端队列,以维护与服务端的多个连接,当调用`Open()`接口时,会在该队列中创建指定个数的客户端,同时通过`System.Threading.Monitor`类实现对队列的同步访问。 - -当请求发生时,会尝试从连接池中寻找一个空闲的客户端连接,如果没有空闲连接,那么程序将需要等待直到有空闲连接 - -当一个连接被用完后,他会自动返回池中等待下次被使用 - -## ByteBuffer - -在传入RPC接口参数时,需要对Record和Tablet两种数据结构进行序列化,我们主要通过封装的ByteBuffer类实现 - -在封装字节序列的基础上,我们进行了内存预申请与内存倍增的优化,减少了序列化过程中内存的申请和释放,在一个拥有20000行的Tablet上进行序列化测试时,速度比起原生的数组动态增长具有**35倍的性能加速** - -### 实现介绍 -在进行`RowRecords`以及`Tablet`的插入时,我们需要对多行RowRecord和Tablet进行序列化以进行发送。客户端中的序列化实现主要依赖于ByteBuffer完成。接下来我们介绍ByteBuffer的实现细节。本文包含如下几点内容: - - 序列化的协议 - - C#与Java的大小端的差异 - - ByteBuffer内存倍增算法 - -### 序列化协议 -客户端向IoTDB服务器发送的序列化数据总体应该包含两个信息。 - - 数据类型 - - 数据本身 - -其中对于`字符串`的序列化时,我们需要再加入字符串的长度信息。即一个字符串的序列化完整结果为: +#### Record - [类型][长度][数据内容] -接下来我们分别介绍`RowRecord`、`Tablet`的序列化方式 +| 方法名 | 参数 | 描述 | 示例 | +| ------------------------------------- | ------------------------------- | ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------- | +| InsertRecordAsync | string, RowRecord | 插入单条记录 | session\_pool.InsertRecordAsync("root.97209\_TEST\_CSHARP\_CLIENT\_GROUP.TEST\_CSHARP\_CLIENT\_DEVICE", new RowRecord(1, values, measures)); | +| InsertRecordsAsync | List, List | 插入多条记录 | session\_pool.InsertRecordsAsync(device\_id, rowRecords) | +| InsertRecordsOfOneDeviceAsync | string, List | 插入同一设备的记录 | session\_pool.InsertRecordsOfOneDeviceAsync(device\_id, rowRecords) | +| InsertRecordsOfOneDeviceSortedAsync | string, List | 插入同一设备的有序记录 | session\_pool.InsertRecordsOfOneDeviceSortedAsync(deviceId, sortedRowRecords); | +| TestInsertRecordAsync | string, RowRecord | 测试插入记录 | session\_pool.TestInsertRecordAsync("root.97209\_TEST\_CSHARP\_CLIENT\_GROUP.TEST\_CSHARP\_CLIENT\_DEVICE", rowRecord) | +| TestInsertRecordsAsync | List, List | 测试插入记录 | session\_pool.TestInsertRecordsAsync(device\_id, rowRecords) | -#### RowRecord -我们对RowRecord进行序列化时,`伪代码`如下: -```csharp -public byte[] value_to_bytes(List data_types, List values){ - ByteBuffer buffer = new ByteBuffer(values.Count); - for(int i = 0;i < data_types.Count(); i++){ - buffer.add_type((data_types[i]); - buffer.add_val(values[i]); - } -} -``` +#### Tablet -对于其序列化的结果格式如下: +| 方法名 | 参数 | 描述 | 示例 | +| ------------------------ | -------------- | ------------------ | ----------------------------------------------- | +| InsertTabletAsync | Tablet | 插入单个 tablet | session\_pool.InsertTabletAsync(tablet) | +| InsertTabletsAsync | List | 插入一批 tablets | session\_pool.InsertTabletsAsync(tablets) | +| TestInsertTabletAsync | Tablet | 测试插入 tablet | session\_pool.TestInsertTabletAsync(tablet) | +| TestInsertTabletsAsync | List | 测试插入 tablets | session\_pool.TestInsertTabletsAsync(tablets) | - [数据类型1][数据1][数据类型2][数据2]...[数据类型N][数据N] - 其中数据类型为自定义的`Enum`变量,分别如下: -```csharp -public enum TSDataType{BOOLEAN, INT32, INT64, FLOAT, DOUBLE, TEXT, NONE}; -``` +### 查询接口 -#### Tablet序列化 -使用`Tabelt`进行数据插入时有如下限制: - - 限制:Tablet中数据不能有空值 -由于向 `IoTDB`服务器发送`Tablet`数据插入请求时会携带`行数`, `列数`, `列数据类型`,所以`Tabelt`序列化时我们不需要加入数据类型信息。`Tablet`是`按照列进行序列化`,这是因为后端可以通过行数得知出当前列的元素个数,同时根据列类型来对数据进行解析。 - -### CSharp与Java序列化数据时的大小端差异 -由于Java序列化默认大端协议,而CSharp序列化默认得到小端序列。所以我们在CSharp中序列化数据之后,需要对数据进行反转这样后端才可以正常解析。同时当我们从后端获取到序列化的结果时(如`SessionDataset`),我们也需要对获得的数据进行反转以解析内容。这其中特例便是字符串的序列化,CSharp中对字符串的序列化结果为大端序,所以序列化字符串或者接收到字符串序列化结果时,不需要反转序列结果。 - -### ByteBuffer内存倍增法 -拥有数万行的Tablet的序列化结果可能有上百兆,为了能够高效的实现大`Tablet`的序列化,我们对ByteBuffer使用`内存倍增法`的策略来减少序列化过程中对于内存的申请和释放。即当当前的buffer的长度不足以放下序列化结果时,我们将当前buffer的内存`至少`扩增2倍。这极大的减少了内存的申请释放次数,加速了大Tablet的序列化速度。 -```csharp -private void extend_buffer(int space_need){ - if(write_pos + space_need >= total_length){ - total_length = max(space_need, total_length); - byte[] new_buffer = new byte[total_length * 2]; - buffer.CopyTo(new_buffer, 0); - buffer = new_buffer; - total_length = 2 * total_length; - } -} -``` -同时在序列化`Tablet`时,我们首先根据Tablet的`行数`,`列数`以及每一列的数据类型估计当前`Tablet`序列化结果所需要的内存大小,并在初始化时进行内存的申请。这进一步的减少了内存的申请释放频率。 +| 方法名 | 参数 | 描述 | 示例 | +| -------------------------------- | -------- | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| ExecuteQueryStatementAsync | string | 执行 SQL 查询语句 | session\_pool.ExecuteQueryStatementAsync("select \* from root.97209\_TEST\_CSHARP\_CLIENT\_GROUP.TEST\_CSHARP\_CLIENT\_DEVICE where time<15"); | +| ExecuteNonQueryStatementAsync| string | 执行 SQL 非查询语句 | session\_pool.ExecuteNonQueryStatementAsync( "create timeseries root.97209\_TEST\_CSHARP\_CLIENT\_GROUP.TEST\_CSHARP\_CLIENT\_DEVICE.status with datatype=BOOLEAN,encoding=PLAIN") | -通过上述的策略,我们在一个有`20000`行的Tablet上进行测试时,序列化速度相比Naive数组长度动态生长实现算法具有约35倍的性能加速。 +### 删除接口 -## 异常重连 +| 方法名 | 参数 | 描述 | 示例 | +| -------------------------- | -------------------------- | ---------------- | -------------------------------------------------------------------------------------- | +| DeleteStorageGroupAsync | string | 删除单个存储组 | session\_pool.DeleteStorageGroupAsync("root.97209\_TEST\_CSHARP\_CLIENT\_GROUP\_01") | +| DeleteStorageGroupsAsync | List | 删除存储组 | session\_pool.DeleteStorageGroupAsync("root.97209\_TEST\_CSHARP\_CLIENT\_GROUP") | +| DeleteTimeSeriesAsync | List | 删除时间序列 | session\_pool.DeleteTimeSeriesAsync(ts\_path\_lst) | +| DeleteTimeSeriesAsync | string | 删除时间序列 | session\_pool.DeleteTimeSeriesAsync(ts\_path) | +| DeleteDataAsync | List, long, long | 删除数据 | session\_pool.DeleteDataAsync(ts\_path\_lst, 2, 3) | -当服务端发生异常或者宕机重启时,客户端中原来通过`Open()`产生的的session会失效,抛出`TException`异常 +## 示例代码 -为了避免这一情况的发生,我们对大部分的接口进行了增强,一旦出现连接问题,就会尝试重新调用`Open()`接口并创建新的Session,并尝试重新发送对应的请求 +完整示例请参考:[Apache.IoTDB.Samples](https://github.com/apache/iotdb-client-csharp/tree/main/samples/Apache.IoTDB.Samples) diff --git a/src/zh/UserGuide/latest/API/Programming-CSharp-Native-API.md b/src/zh/UserGuide/latest/API/Programming-CSharp-Native-API.md index d8997bff6..40f0b49b3 100644 --- a/src/zh/UserGuide/latest/API/Programming-CSharp-Native-API.md +++ b/src/zh/UserGuide/latest/API/Programming-CSharp-Native-API.md @@ -21,34 +21,32 @@ # C# 原生接口 -## 1. 依赖 +## 1. 环境要求 -- .NET SDK >= 5.0 或 .NET Framework 4.x -- Thrift >= 0.14.1 -- NLog >= 4.7.9 +* .NET SDK >= 5.0 或 .NET Framework 4.x +* Thrift >= 0.14.1 +* NLog >= 4.7.9 -## 2. 安装 +## 2. 依赖安装 您可以使用 NuGet Package Manager, .NET CLI等工具来安装,以 .NET CLI为例 -如果您使用的是\.NET 5.0 或者更高版本的SDK,输入如下命令即可安装最新的NuGet包 +如果您使用的是.NET 5.0 或者更高版本的SDK,输入如下命令即可安装最新的NuGet包 -``` +```Bash dotnet add package Apache.IoTDB ``` 如果您想安装更早版本的客户端,只需要指定版本即可 -```bash +```Bash # 安装0.12.1.2版本的客户端 dotnet add package Apache.IoTDB --version 0.12.1.2 ``` -## 3. 基本接口说明 - -Session接口在语义上和其他语言客户端相同 +## 3. 快速入门 -```csharp +```C# // 参数定义 string host = "localhost"; int port = 6667; @@ -82,187 +80,87 @@ await session_pool.InsertTabletAsync(tablet); await session_pool.Close(); ``` -## 4. **Row Record** +## 4. 全量接口说明 -- 对**IoTDB**中的`record`数据进行封装和抽象。 -- 示例: +SessionPool 连接池支持并发客户端请求,线程安全。当 `pool_size`设为 1 时,其行为等同于单个 session。推荐使用 SessionPool ,作为实现与数据库交互的核心接口,SessionPool 集成了丰富的方法,支持数据写入、查询以及元数据操作等功能,详细介绍见下文。 - | timestamp | status | temperature | - | --------- | ------ | ----------- | - | 1 | 0 | 20 | +### 4.1 基础接口 -- 构造方法: +| 方法名 | 参数 | 描述 | 示例 | +| ---------------- | --------------------------- | -------------- | -------------------------------- | +| Open | bool | 打开会话 | session\_pool.Open(false) | +| Close | null | 关闭会话 | session\_pool.Close() | +| IsOpen | null | 查看会话状态 | session\_pool.IsOpen() | +| OpenDebugMode | LoggingConfiguration=null | 启用调试模式 | session\_pool.OpenDebugMode() | +| CloseDebugMode | null | 禁用调试模式 | session\_pool.CloseDebugMode() | +| SetTimeZone | string | 设置时区 | session\_pool.GetTimeZone() | +| GetTimeZone | null | 获取时区 | session\_pool.GetTimeZone() | -```csharp -var rowRecord = - new RowRecord(long timestamps, List values, List measurements); -``` +### 4.2 元数据接口 -### 4.1 **Tablet** +| 方法名 | 参数 | 描述 | 示例 | +| ---------------------------- | ---------------------------------------------------------------------- | ---------------------- | ----------------------------------------------------------------------------------------------------------- | +| SetStorageGroup | string | (创建)存储组 | session\_pool.SetStorageGroup("root.97209\_TEST\_CSHARP\_CLIENT\_GROUP\_01") | +| CreateTimeSeries | string, TSDataType, TSEncoding, Compressor | 创建时间序列 | session\_pool.InsertTabletsAsync(tablets) | +| CreateMultiTimeSeriesAsync | List, List , List , List | 创建多个时间序列 | session\_pool.CreateMultiTimeSeriesAsync(ts\_path\_lst, data\_type\_lst, encoding\_lst, compressor\_lst); | +| CheckTimeSeriesExistsAsync | string | 查看时间序列是否存在 | session\_pool.CheckTimeSeriesExistsAsync(time series) | -- 一种类似于表格的数据结构,包含一个设备的若干行非空数据块。 -- 示例: +### 4.3 写入接口 - | time | status | temperature | - | ---- | ------ | ----------- | - | 1 | 0 | 20 | - | 2 | 0 | 20 | - | 3 | 3 | 21 | +C# 原生接口支持通过 Record 和 Tablet 两种方式进行数据写入: -- 构造方法: +* RowRecord 是对 IoTDB 中的`record`数据进行封装和抽象,适合单行数据写入的场景,其构造方法如下 -```csharp -var tablet = - Tablet(string deviceId, List measurements, List> values, List timestamps); +```C# +var rowRecord = + new RowRecord(long timestamps, List values, List measurements); ``` +* Tablet 是一种类似于表格的数据结构,适合一个设备若干行非空数据块写入的场景,其构造方法如下 +```C# +var tablet = + new Tablet(string deviceId, List measurements, List> values, List timestamps); +``` -## 5. **API** - -### 5.1 **基础接口** - -| api name | parameters | notes | use example | -| -------------- | ------------------------- | ------------------------ | ----------------------------- | -| Open | bool | open session | session_pool.Open(false) | -| Close | null | close session | session_pool.Close() | -| IsOpen | null | check if session is open | session_pool.IsOpen() | -| OpenDebugMode | LoggingConfiguration=null | open debug mode | session_pool.OpenDebugMode() | -| CloseDebugMode | null | close debug mode | session_pool.CloseDebugMode() | -| SetTimeZone | string | set time zone | session_pool.GetTimeZone() | -| GetTimeZone | null | get time zone | session_pool.GetTimeZone() | - -### 5.2 **Record相关接口** - -| api name | parameters | notes | use example | -| ----------------------------------- | ----------------------------- | ----------------------------------- | ------------------------------------------------------------ | -| InsertRecordAsync | string, RowRecord | insert single record | session_pool.InsertRecordAsync("root.97209_TEST_CSHARP_CLIENT_GROUP.TEST_CSHARP_CLIENT_DEVICE", new RowRecord(1, values, measures)); | -| InsertRecordsAsync | List\, List\ | insert records | session_pool.InsertRecordsAsync(device_id, rowRecords) | -| InsertRecordsOfOneDeviceAsync | string, List\ | insert records of one device | session_pool.InsertRecordsOfOneDeviceAsync(device_id, rowRecords) | -| InsertRecordsOfOneDeviceSortedAsync | string, List\ | insert sorted records of one device | InsertRecordsOfOneDeviceSortedAsync(deviceId, sortedRowRecords); | -| TestInsertRecordAsync | string, RowRecord | test insert record | session_pool.TestInsertRecordAsync("root.97209_TEST_CSHARP_CLIENT_GROUP.TEST_CSHARP_CLIENT_DEVICE", rowRecord) | -| TestInsertRecordsAsync | List\, List\ | test insert record | session_pool.TestInsertRecordsAsync(device_id, rowRecords) | - -### 5.3 **Tablet相关接口** - -| api name | parameters | notes | use example | -| ---------------------- | ------------ | -------------------- | -------------------------------------------- | -| InsertTabletAsync | Tablet | insert single tablet | session_pool.InsertTabletAsync(tablet) | -| InsertTabletsAsync | List\ | insert tablets | session_pool.InsertTabletsAsync(tablets) | -| TestInsertTabletAsync | Tablet | test insert tablet | session_pool.TestInsertTabletAsync(tablet) | -| TestInsertTabletsAsync | List\ | test insert tablets | session_pool.TestInsertTabletsAsync(tablets) | - -### 5.4 **SQL语句接口** - -| api name | parameters | notes | use example | -| ----------------------------- | ---------- | ------------------------------ | ------------------------------------------------------------ | -| ExecuteQueryStatementAsync | string | execute sql query statement | session_pool.ExecuteQueryStatementAsync("select * from root.97209_TEST_CSHARP_CLIENT_GROUP.TEST_CSHARP_CLIENT_DEVICE where time<15"); | -| ExecuteNonQueryStatementAsync | string | execute sql nonquery statement | session_pool.ExecuteNonQueryStatementAsync( "create timeseries root.97209_TEST_CSHARP_CLIENT_GROUP.TEST_CSHARP_CLIENT_DEVICE.status with datatype=BOOLEAN,encoding=PLAIN") | - -### 5.5 数据表接口 - -| api name | parameters | notes | use example | -| -------------------------- | ------------------------------------------------------------ | --------------------------- | ------------------------------------------------------------ | -| SetStorageGroup | string | set storage group | session_pool.SetStorageGroup("root.97209_TEST_CSHARP_CLIENT_GROUP_01") | -| CreateTimeSeries | string, TSDataType, TSEncoding, Compressor | create time series | session_pool.InsertTabletsAsync(tablets) | -| DeleteStorageGroupAsync | string | delete single storage group | session_pool.DeleteStorageGroupAsync("root.97209_TEST_CSHARP_CLIENT_GROUP_01") | -| DeleteStorageGroupsAsync | List\ | delete storage group | session_pool.DeleteStorageGroupAsync("root.97209_TEST_CSHARP_CLIENT_GROUP") | -| CreateMultiTimeSeriesAsync | List\, List\ , List\ , List\ | create multi time series | session_pool.CreateMultiTimeSeriesAsync(ts_path_lst, data_type_lst, encoding_lst, compressor_lst); | -| DeleteTimeSeriesAsync | List\ | delete time series | | -| DeleteTimeSeriesAsync | string | delete time series | | -| DeleteDataAsync | List\, long, long | delete data | session_pool.DeleteDataAsync(ts_path_lst, 2, 3) | - -### 5.6 **辅助接口** - -| api name | parameters | notes | use example | -| -------------------------- | ---------- | --------------------------- | ---------------------------------------------------- | -| CheckTimeSeriesExistsAsync | string | check if time series exists | session_pool.CheckTimeSeriesExistsAsync(time series) | - - - -用法可以参考[用户示例](https://github.com/apache/iotdb-client-csharp/tree/main/samples/Apache.IoTDB.Samples) - -## 6. 连接池 - -为了实现并发客户端请求,我们提供了针对原生接口的连接池(`SessionPool`),由于`SessionPool`本身为`Session`的超集,当`SessionPool`的`pool_size`参数设置为1时,退化为原来的`Session` - -我们使用`ConcurrentQueue`数据结构封装了一个客户端队列,以维护与服务端的多个连接,当调用`Open()`接口时,会在该队列中创建指定个数的客户端,同时通过`System.Threading.Monitor`类实现对队列的同步访问。 - -当请求发生时,会尝试从连接池中寻找一个空闲的客户端连接,如果没有空闲连接,那么程序将需要等待直到有空闲连接 - -当一个连接被用完后,他会自动返回池中等待下次被使用 - -## 7. ByteBuffer - -在传入RPC接口参数时,需要对Record和Tablet两种数据结构进行序列化,我们主要通过封装的ByteBuffer类实现 - -在封装字节序列的基础上,我们进行了内存预申请与内存倍增的优化,减少了序列化过程中内存的申请和释放,在一个拥有20000行的Tablet上进行序列化测试时,速度比起原生的数组动态增长具有**35倍的性能加速** - -### 7.1 实现介绍 -在进行`RowRecords`以及`Tablet`的插入时,我们需要对多行RowRecord和Tablet进行序列化以进行发送。客户端中的序列化实现主要依赖于ByteBuffer完成。接下来我们介绍ByteBuffer的实现细节。本文包含如下几点内容: - - 序列化的协议 - - C#与Java的大小端的差异 - - ByteBuffer内存倍增算法 - -### 7.2 序列化协议 -客户端向IoTDB服务器发送的序列化数据总体应该包含两个信息。 - - 数据类型 - - 数据本身 - -其中对于`字符串`的序列化时,我们需要再加入字符串的长度信息。即一个字符串的序列化完整结果为: +#### 4.3.1 Record - [类型][长度][数据内容] -接下来我们分别介绍`RowRecord`、`Tablet`的序列化方式 +| 方法名 | 参数 | 描述 | 示例 | +| ------------------------------------- | ------------------------------- | ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------- | +| InsertRecordAsync | string, RowRecord | 插入单条记录 | session\_pool.InsertRecordAsync("root.97209\_TEST\_CSHARP\_CLIENT\_GROUP.TEST\_CSHARP\_CLIENT\_DEVICE", new RowRecord(1, values, measures)); | +| InsertRecordsAsync | List, List | 插入多条记录 | session\_pool.InsertRecordsAsync(device\_id, rowRecords) | +| InsertRecordsOfOneDeviceAsync | string, List | 插入同一设备的记录 | session\_pool.InsertRecordsOfOneDeviceAsync(device\_id, rowRecords) | +| InsertRecordsOfOneDeviceSortedAsync | string, List | 插入同一设备的有序记录 | session\_pool.InsertRecordsOfOneDeviceSortedAsync(deviceId, sortedRowRecords); | +| TestInsertRecordAsync | string, RowRecord | 测试插入记录 | session\_pool.TestInsertRecordAsync("root.97209\_TEST\_CSHARP\_CLIENT\_GROUP.TEST\_CSHARP\_CLIENT\_DEVICE", rowRecord) | +| TestInsertRecordsAsync | List, List | 测试插入记录 | session\_pool.TestInsertRecordsAsync(device\_id, rowRecords) | -#### RowRecord -我们对RowRecord进行序列化时,`伪代码`如下: -```csharp -public byte[] value_to_bytes(List data_types, List values){ - ByteBuffer buffer = new ByteBuffer(values.Count); - for(int i = 0;i < data_types.Count(); i++){ - buffer.add_type((data_types[i]); - buffer.add_val(values[i]); - } -} -``` +#### 4.3.2 Tablet -对于其序列化的结果格式如下: +| 方法名 | 参数 | 描述 | 示例 | +| ------------------------ | -------------- | ------------------ | ----------------------------------------------- | +| InsertTabletAsync | Tablet | 插入单个 tablet | session\_pool.InsertTabletAsync(tablet) | +| InsertTabletsAsync | List | 插入一批 tablets | session\_pool.InsertTabletsAsync(tablets) | +| TestInsertTabletAsync | Tablet | 测试插入 tablet | session\_pool.TestInsertTabletAsync(tablet) | +| TestInsertTabletsAsync | List | 测试插入 tablets | session\_pool.TestInsertTabletsAsync(tablets) | - [数据类型1][数据1][数据类型2][数据2]...[数据类型N][数据N] - 其中数据类型为自定义的`Enum`变量,分别如下: -```csharp -public enum TSDataType{BOOLEAN, INT32, INT64, FLOAT, DOUBLE, TEXT, NONE}; -``` +### 4.4 查询接口 -#### Tablet序列化 -使用`Tabelt`进行数据插入时有如下限制: - - 限制:Tablet中数据不能有空值 -由于向 `IoTDB`服务器发送`Tablet`数据插入请求时会携带`行数`, `列数`, `列数据类型`,所以`Tabelt`序列化时我们不需要加入数据类型信息。`Tablet`是`按照列进行序列化`,这是因为后端可以通过行数得知出当前列的元素个数,同时根据列类型来对数据进行解析。 - -### 7.3 CSharp与Java序列化数据时的大小端差异 -由于Java序列化默认大端协议,而CSharp序列化默认得到小端序列。所以我们在CSharp中序列化数据之后,需要对数据进行反转这样后端才可以正常解析。同时当我们从后端获取到序列化的结果时(如`SessionDataset`),我们也需要对获得的数据进行反转以解析内容。这其中特例便是字符串的序列化,CSharp中对字符串的序列化结果为大端序,所以序列化字符串或者接收到字符串序列化结果时,不需要反转序列结果。 - -### 7.4 ByteBuffer内存倍增法 -拥有数万行的Tablet的序列化结果可能有上百兆,为了能够高效的实现大`Tablet`的序列化,我们对ByteBuffer使用`内存倍增法`的策略来减少序列化过程中对于内存的申请和释放。即当当前的buffer的长度不足以放下序列化结果时,我们将当前buffer的内存`至少`扩增2倍。这极大的减少了内存的申请释放次数,加速了大Tablet的序列化速度。 -```csharp -private void extend_buffer(int space_need){ - if(write_pos + space_need >= total_length){ - total_length = max(space_need, total_length); - byte[] new_buffer = new byte[total_length * 2]; - buffer.CopyTo(new_buffer, 0); - buffer = new_buffer; - total_length = 2 * total_length; - } -} -``` -同时在序列化`Tablet`时,我们首先根据Tablet的`行数`,`列数`以及每一列的数据类型估计当前`Tablet`序列化结果所需要的内存大小,并在初始化时进行内存的申请。这进一步的减少了内存的申请释放频率。 +| 方法名 | 参数 | 描述 | 示例 | +| -------------------------------- | -------- | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| ExecuteQueryStatementAsync | string | 执行 SQL 查询语句 | session\_pool.ExecuteQueryStatementAsync("select \* from root.97209\_TEST\_CSHARP\_CLIENT\_GROUP.TEST\_CSHARP\_CLIENT\_DEVICE where time<15"); | +| ExecuteNonQueryStatementAsync| string | 执行 SQL 非查询语句 | session\_pool.ExecuteNonQueryStatementAsync( "create timeseries root.97209\_TEST\_CSHARP\_CLIENT\_GROUP.TEST\_CSHARP\_CLIENT\_DEVICE.status with datatype=BOOLEAN,encoding=PLAIN") | -通过上述的策略,我们在一个有`20000`行的Tablet上进行测试时,序列化速度相比Naive数组长度动态生长实现算法具有约35倍的性能加速。 +### 4.5 删除接口 -## 8. 异常重连 +| 方法名 | 参数 | 描述 | 示例 | +| -------------------------- | -------------------------- | ---------------- | -------------------------------------------------------------------------------------- | +| DeleteStorageGroupAsync | string | 删除单个存储组 | session\_pool.DeleteStorageGroupAsync("root.97209\_TEST\_CSHARP\_CLIENT\_GROUP\_01") | +| DeleteStorageGroupsAsync | List | 删除存储组 | session\_pool.DeleteStorageGroupAsync("root.97209\_TEST\_CSHARP\_CLIENT\_GROUP") | +| DeleteTimeSeriesAsync | List | 删除时间序列 | session\_pool.DeleteTimeSeriesAsync(ts\_path\_lst) | +| DeleteTimeSeriesAsync | string | 删除时间序列 | session\_pool.DeleteTimeSeriesAsync(ts\_path) | +| DeleteDataAsync | List, long, long | 删除数据 | session\_pool.DeleteDataAsync(ts\_path\_lst, 2, 3) | -当服务端发生异常或者宕机重启时,客户端中原来通过`Open()`产生的的session会失效,抛出`TException`异常 +## 5. 示例代码 -为了避免这一情况的发生,我们对大部分的接口进行了增强,一旦出现连接问题,就会尝试重新调用`Open()`接口并创建新的Session,并尝试重新发送对应的请求 +完整示例请参考:[Apache.IoTDB.Samples](https://github.com/apache/iotdb-client-csharp/tree/main/samples/Apache.IoTDB.Samples)