Merge branch 'develop' into hotfix/fileinfo
This commit is contained in:
commit
ad67d25ddf
|
@ -46,7 +46,6 @@ html/
|
|||
/CMakeCache.txt
|
||||
/Makefile
|
||||
/*.cmake
|
||||
/deps
|
||||
/src/cq/test/CMakeFiles/cqtest.dir/*.cmake
|
||||
*.cmake
|
||||
/src/cq/test/CMakeFiles/cqtest.dir/*.make
|
||||
|
@ -65,3 +64,4 @@ CMakeError.log
|
|||
/out/isenseconfig/WSL-Clang-Debug
|
||||
/out/isenseconfig/WSL-GCC-Debug
|
||||
/test/cfg
|
||||
/src/.vs
|
||||
|
|
11
.travis.yml
11
.travis.yml
|
@ -51,7 +51,7 @@ matrix:
|
|||
./test-all.sh $TRAVIS_EVENT_TYPE || travis_terminate $?
|
||||
|
||||
cd ${TRAVIS_BUILD_DIR}/tests/pytest
|
||||
./valgrind-test.sh 2>&1 > mem-error-out.txt
|
||||
./valgrind-test.sh 2>&1 > mem-error-out.log
|
||||
sleep 1
|
||||
|
||||
# Color setting
|
||||
|
@ -61,9 +61,9 @@ matrix:
|
|||
GREEN_UNDERLINE='\033[4;32m'
|
||||
NC='\033[0m'
|
||||
|
||||
grep 'start to execute\|ERROR SUMMARY' mem-error-out.txt|grep -v 'grep'|uniq|tee uniq-mem-error-out.txt
|
||||
grep 'start to execute\|ERROR SUMMARY' mem-error-out.log|grep -v 'grep'|uniq|tee uniq-mem-error-out.log
|
||||
|
||||
for memError in `grep 'ERROR SUMMARY' uniq-mem-error-out.txt | awk '{print $4}'`
|
||||
for memError in `grep 'ERROR SUMMARY' uniq-mem-error-out.log | awk '{print $4}'`
|
||||
do
|
||||
if [ -n "$memError" ]; then
|
||||
if [ "$memError" -gt 12 ]; then
|
||||
|
@ -74,8 +74,8 @@ matrix:
|
|||
fi
|
||||
done
|
||||
|
||||
grep 'start to execute\|definitely lost:' mem-error-out.txt|grep -v 'grep'|uniq|tee uniq-definitely-lost-out.txt
|
||||
for defiMemError in `grep 'definitely lost:' uniq-definitely-lost-out.txt | awk '{print $7}'`
|
||||
grep 'start to execute\|definitely lost:' mem-error-out.log|grep -v 'grep'|uniq|tee uniq-definitely-lost-out.log
|
||||
for defiMemError in `grep 'definitely lost:' uniq-definitely-lost-out.log | awk '{print $7}'`
|
||||
do
|
||||
if [ -n "$defiMemError" ]; then
|
||||
if [ "$defiMemError" -gt 13 ]; then
|
||||
|
@ -177,6 +177,7 @@ matrix:
|
|||
|
||||
cd ${TRAVIS_BUILD_DIR}
|
||||
lcov -d . --capture --rc lcov_branch_coverage=1 -o coverage.info
|
||||
lcov --remove coverage.info '*tests*' '*deps*' -o coverage.info
|
||||
lcov -l --rc lcov_branch_coverage=1 coverage.info || travis_terminate $?
|
||||
|
||||
gem install coveralls-lcov
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
"generator": "Unix Makefiles",
|
||||
"configurationType": "Debug",
|
||||
"buildRoot": "${projectDir}\\build\\",
|
||||
"installRoot": "${projectDir}\\out\\install\\${name}",
|
||||
"installRoot": "${projectDir}\\build\\",
|
||||
"cmakeExecutable": "/usr/bin/cmake",
|
||||
"cmakeCommandArgs": "",
|
||||
"buildCommandArgs": "",
|
||||
|
|
|
@ -44,7 +44,7 @@ sudo apt-get install maven
|
|||
Build TDengine:
|
||||
|
||||
```
|
||||
mkdir build && cd build
|
||||
mkdir debug && cd debug
|
||||
cmake .. && cmake --build .
|
||||
```
|
||||
|
||||
|
|
|
@ -7,3 +7,4 @@ ADD_SUBDIRECTORY(regex)
|
|||
ADD_SUBDIRECTORY(iconv)
|
||||
ADD_SUBDIRECTORY(lz4)
|
||||
ADD_SUBDIRECTORY(cJson)
|
||||
ADD_SUBDIRECTORY(MQTT-C)
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
cmake_minimum_required(VERSION 3.5)
|
||||
project(MQTT-C VERSION 1.1.2 LANGUAGES C)
|
||||
|
||||
# MQTT-C build options
|
||||
option(MQTT_C_OpenSSL_SUPPORT "Build MQTT-C with OpenSSL support?" OFF)
|
||||
option(MQTT_C_MbedTLS_SUPPORT "Build MQTT-C with mbed TLS support?" OFF)
|
||||
option(MQTT_C_EXAMPLES "Build MQTT-C examples?" ON)
|
||||
option(MQTT_C_TESTS "Build MQTT-C tests?" OFF)
|
||||
|
||||
list (APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
|
||||
|
||||
# MQTT-C library
|
||||
add_library(mqttc STATIC
|
||||
src/mqtt_pal.c
|
||||
src/mqtt.c
|
||||
)
|
||||
target_include_directories(mqttc PUBLIC include)
|
||||
target_link_libraries(mqttc PUBLIC
|
||||
$<$<C_COMPILER_ID:MSVS>:ws2_32>
|
||||
)
|
||||
|
||||
|
||||
# Configure with OpenSSL support
|
||||
if(MQTT_C_OpenSSL_SUPPORT)
|
||||
find_package(OpenSSL REQUIRED)
|
||||
target_link_libraries(mqttc INTERFACE OpenSSL::SSL)
|
||||
target_compile_definitions(mqttc PUBLIC MQTT_USE_BIO)
|
||||
endif()
|
||||
|
||||
# Configure with mbed TLS support
|
||||
if(MQTT_C_MbedTLS_SUPPORT)
|
||||
find_package(MbedTLS REQUIRED)
|
||||
target_include_directories(mqttc PUBLIC ${MBEDTLS_INCLUDE_DIRS})
|
||||
target_link_libraries(mqttc INTERFACE ${MBEDTLS_LIBRARY})
|
||||
target_compile_definitions(mqttc PUBLIC MQTT_USE_MBEDTLS)
|
||||
endif()
|
||||
|
||||
# Build examples
|
||||
if(MQTT_C_EXAMPLES)
|
||||
find_package(Threads REQUIRED)
|
||||
|
||||
if(MQTT_C_OpenSSL_SUPPORT)
|
||||
add_executable(bio_publisher examples/bio_publisher.c)
|
||||
target_link_libraries(bio_publisher Threads::Threads mqttc)
|
||||
|
||||
add_executable(openssl_publisher examples/openssl_publisher.c)
|
||||
target_link_libraries(openssl_publisher Threads::Threads mqttc)
|
||||
elseif(MQTT_C_MbedTLS_SUPPORT)
|
||||
add_executable(mbedtls_publisher examples/mbedtls_publisher.c)
|
||||
target_link_libraries(mbedtls_publisher Threads::Threads mqttc ${MBEDX509_LIBRARY} ${MBEDCRYPTO_LIBRARY})
|
||||
else()
|
||||
add_executable(simple_publisher examples/simple_publisher.c)
|
||||
target_link_libraries(simple_publisher Threads::Threads mqttc)
|
||||
|
||||
add_executable(simple_subscriber examples/simple_subscriber.c)
|
||||
target_link_libraries(simple_subscriber Threads::Threads mqttc)
|
||||
|
||||
add_executable(reconnect_subscriber examples/reconnect_subscriber.c)
|
||||
target_link_libraries(reconnect_subscriber Threads::Threads mqttc)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Build tests
|
||||
if(MQTT_C_TESTS)
|
||||
find_path(CMOCKA_INCLUDE_DIR cmocka.h)
|
||||
find_library(CMOCKA_LIBRARY cmocka)
|
||||
if((NOT CMOCKA_INCLUDE_DIR) OR (NOT CMOCKA_LIBRARY))
|
||||
message(FATAL_ERROR "Failed to find cmocka! Add cmocka's install prefix to CMAKE_PREFIX_PATH to resolve this error.")
|
||||
endif()
|
||||
|
||||
add_executable(tests tests.c)
|
||||
target_link_libraries(tests ${CMOCKA_LIBRARY} mqttc)
|
||||
target_include_directories(tests PRIVATE ${CMOCKA_INCLUDE_DIR})
|
||||
endif()
|
||||
|
||||
# Install includes and library
|
||||
# install(TARGETS mqttc
|
||||
# DESTINATION lib
|
||||
# )
|
||||
# install(DIRECTORY include/
|
||||
# DESTINATION include)
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2018 Liam Bindle
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
|
@ -0,0 +1,108 @@
|
|||
<p align="right">
|
||||
<a href="https://github.com/LiamBindle/MQTT-C/stargazers"><img src="https://img.shields.io/github/stars/LiamBindle/MQTT-C.svg?style=social&label=Star" style="margin-left:5em"></a>
|
||||
<a href="https://github.com/LiamBindle/MQTT-C/network/members"><img src="https://img.shields.io/github/forks/LiamBindle/MQTT-C.svg?style=social&label=Fork"></a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<img width="70%" src="docs/mqtt-c-logo.png"><br>
|
||||
<a href="https://liambindle.ca/MQTT-C"><img src="https://img.shields.io/badge/docs-passing-brightgreen.svg"></a>
|
||||
<a href="https://github.com/LiamBindle/MQTT-C/issues"><img src="https://img.shields.io/badge/Maintained%3F-yes-green.svg"></a>
|
||||
<a href="https://GitHub.com/LiamBindle/MQTT-C/issues/"><img src="https://img.shields.io/github/issues/LiamBindle/MQTT-C.svg"></a>
|
||||
<a href="https://github.com/LiamBindle/MQTT-C/issues"><img src="https://img.shields.io/github/issues-closed/LiamBindle/MQTT-C.svg"></a>
|
||||
<a href="https://github.com/LiamBindle/MQTT-C/blob/master/LICENSE"><img src="https://img.shields.io/badge/License-MIT-blue.svg"></a>
|
||||
</p>
|
||||
|
||||
#
|
||||
|
||||
MQTT-C is an [MQTT v3.1.1](http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html)
|
||||
client written in C. MQTT is a lightweight publisher-subscriber-based messaging protocol that is
|
||||
commonly used in IoT and networking applications where high-latency and low data-rate links
|
||||
are expected. The purpose of MQTT-C is to provide a **portable** MQTT client, **written in C**,
|
||||
for embedded systems and PC's alike. MQTT-C does this by providing a transparent Platform
|
||||
Abstraction Layer (PAL) which makes porting to new platforms easy. MQTT-C is completely
|
||||
thread-safe but can also run perfectly fine on single-threaded systems making MQTT-C
|
||||
well-suited for embedded systems and microcontrollers. Finally, MQTT-C is small; there are only
|
||||
two source files totalling less than 2000 lines.
|
||||
|
||||
#### A note from the author
|
||||
It's been great to hear about all the places MQTT-C is being used! Please don't hesitate
|
||||
to get in touch with me or submit issues on GitHub!
|
||||
|
||||
## Getting Started
|
||||
To use MQTT-C you first instantiate a `struct mqtt_client` and initialize it by calling
|
||||
@ref mqtt_init.
|
||||
```c
|
||||
struct mqtt_client client; /* instantiate the client */
|
||||
mqtt_init(&client, ...); /* initialize the client */
|
||||
```
|
||||
Once your client is initialized you need to connect to an MQTT broker.
|
||||
```c
|
||||
mqtt_connect(&client, ...); /* send a connection request to the broker. */
|
||||
```
|
||||
At this point the client is ready to use! For example, we can subscribe to a topic like so:
|
||||
```c
|
||||
/* subscribe to "toaster/temperature" with a max QoS level of 0 */
|
||||
mqtt_subscribe(&client, "toaster/temperature", 0);
|
||||
```
|
||||
And we can publish to a topic like so:
|
||||
```c
|
||||
/* publish coffee temperature with a QoS level of 1 */
|
||||
int temperature = 67;
|
||||
mqtt_publish(&client, "coffee/temperature", &temperature, sizeof(int), MQTT_PUBLISH_QOS_1);
|
||||
```
|
||||
Those are the basics! From here the [examples](https://github.com/LiamBindle/MQTT-C/tree/master/examples) and [API documentation](https://liambindle.ca/MQTT-C/group__api.html) are good places to get started.
|
||||
|
||||
## Building
|
||||
There are **only two source files** that need to be built, `mqtt.c` and `mqtt_pal.c`.
|
||||
These files are ANSI C (C89) compatible, and should compile with any C compiler.
|
||||
|
||||
Then, simply <code>\#include <mqtt.h></code>.
|
||||
|
||||
Alternatively, you can build MQTT-C with CMake or the provided Makefile. These are provided for convenience.
|
||||
|
||||
## Documentation
|
||||
Pre-built documentation can be found here: [https://liambindle.ca/MQTT-C](https://liambindle.ca/MQTT-C). Be sure to check out the [examples](https://github.com/LiamBindle/MQTT-C/tree/master/examples) too.
|
||||
|
||||
The @ref api documentation contains all the documentation application programmers should need.
|
||||
The @ref pal documentation contains everything you should need to port MQTT-C to a new platform,
|
||||
and the other modules contain documentation for MQTT-C developers.
|
||||
|
||||
## Testing and Building the Tests
|
||||
The MQTT-C unit tests use the [cmocka unit testing framework](https://cmocka.org/).
|
||||
Therefore, [cmocka](https://cmocka.org/) *must* be installed on your machine to build and run
|
||||
the unit tests. For convenience, a simple `"makefile"` is included to build the unit tests and
|
||||
examples on UNIX-like machines. The unit tests and examples can be built as follows:
|
||||
```bash
|
||||
$ make all
|
||||
```
|
||||
The unit tests and examples will be built in the `"bin/"` directory. The unit tests can be run
|
||||
like so:
|
||||
```bash
|
||||
$ ./bin/tests [address [port]]
|
||||
```
|
||||
Note that the \c address and \c port arguments are both optional to specify the location of the
|
||||
MQTT broker that is to be used for the tests. If no \c address is given then the
|
||||
[Mosquitto MQTT Test Server](https://test.mosquitto.org/) will be used. If no \c port is given,
|
||||
port 1883 will be used.
|
||||
|
||||
## Portability
|
||||
MQTT-C provides a transparent platform abstraction layer (PAL) in `mqtt_pal.h` and `mqtt_pal.c`.
|
||||
These files declare and implement the types and calls that MQTT-C requires. Refer to
|
||||
@ref pal for the complete documentation of the PAL.
|
||||
|
||||
## Contributing
|
||||
Please feel free to submit issues and pull-requests [here](https://github.com/LiamBindle/MQTT-C).
|
||||
When submitting a pull-request please ensure you have *fully documented* your changes and
|
||||
added the appropriate unit tests.
|
||||
|
||||
|
||||
## License
|
||||
This project is licensed under the [MIT License](https://opensource.org/licenses/MIT). See the
|
||||
`"LICENSE"` file for more details.
|
||||
|
||||
## Authors
|
||||
MQTT-C was initially developed as a CMPT 434 (Winter Term, 2018) final project at the University of
|
||||
Saskatchewan by:
|
||||
- **Liam Bindle**
|
||||
- **Demilade Adeoye**
|
||||
|
|
@ -0,0 +1,156 @@
|
|||
|
||||
/**
|
||||
* @file
|
||||
* A simple program to that publishes the current time whenever ENTER is pressed.
|
||||
*/
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <mqtt.h>
|
||||
#include "templates/bio_sockets.h"
|
||||
|
||||
|
||||
/**
|
||||
* @brief The function that would be called whenever a PUBLISH is received.
|
||||
*
|
||||
* @note This function is not used in this example.
|
||||
*/
|
||||
void publish_callback(void** unused, struct mqtt_response_publish *published);
|
||||
|
||||
/**
|
||||
* @brief The client's refresher. This function triggers back-end routines to
|
||||
* handle ingress/egress traffic to the broker.
|
||||
*
|
||||
* @note All this function needs to do is call \ref __mqtt_recv and
|
||||
* \ref __mqtt_send every so often. I've picked 100 ms meaning that
|
||||
* client ingress/egress traffic will be handled every 100 ms.
|
||||
*/
|
||||
void* client_refresher(void* client);
|
||||
|
||||
/**
|
||||
* @brief Safelty closes the \p sockfd and cancels the \p client_daemon before \c exit.
|
||||
*/
|
||||
void exit_example(int status, BIO* sockfd, pthread_t *client_daemon);
|
||||
|
||||
/**
|
||||
* A simple program to that publishes the current time whenever ENTER is pressed.
|
||||
*/
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
const char* addr;
|
||||
const char* port;
|
||||
const char* topic;
|
||||
|
||||
/* Load OpenSSL */
|
||||
SSL_load_error_strings();
|
||||
ERR_load_BIO_strings();
|
||||
OpenSSL_add_all_algorithms();
|
||||
|
||||
/* get address (argv[1] if present) */
|
||||
if (argc > 1) {
|
||||
addr = argv[1];
|
||||
} else {
|
||||
addr = "test.mosquitto.org";
|
||||
}
|
||||
|
||||
/* get port number (argv[2] if present) */
|
||||
if (argc > 2) {
|
||||
port = argv[2];
|
||||
} else {
|
||||
port = "1883";
|
||||
}
|
||||
|
||||
/* get the topic name to publish */
|
||||
if (argc > 3) {
|
||||
topic = argv[3];
|
||||
} else {
|
||||
topic = "datetime";
|
||||
}
|
||||
|
||||
/* open the non-blocking TCP socket (connecting to the broker) */
|
||||
BIO* sockfd = open_nb_socket(addr, port);
|
||||
|
||||
if (sockfd == NULL) {
|
||||
exit_example(EXIT_FAILURE, sockfd, NULL);
|
||||
}
|
||||
|
||||
/* setup a client */
|
||||
struct mqtt_client client;
|
||||
uint8_t sendbuf[2048]; /* sendbuf should be large enough to hold multiple whole mqtt messages */
|
||||
uint8_t recvbuf[1024]; /* recvbuf should be large enough any whole mqtt message expected to be received */
|
||||
mqtt_init(&client, sockfd, sendbuf, sizeof(sendbuf), recvbuf, sizeof(recvbuf), publish_callback);
|
||||
mqtt_connect(&client, "publishing_client", NULL, NULL, 0, NULL, NULL, 0, 400);
|
||||
|
||||
/* check that we don't have any errors */
|
||||
if (client.error != MQTT_OK) {
|
||||
fprintf(stderr, "error: %s\n", mqtt_error_str(client.error));
|
||||
exit_example(EXIT_FAILURE, sockfd, NULL);
|
||||
}
|
||||
|
||||
/* start a thread to refresh the client (handle egress and ingree client traffic) */
|
||||
pthread_t client_daemon;
|
||||
if(pthread_create(&client_daemon, NULL, client_refresher, &client)) {
|
||||
fprintf(stderr, "Failed to start client daemon.\n");
|
||||
exit_example(EXIT_FAILURE, sockfd, NULL);
|
||||
|
||||
}
|
||||
|
||||
/* start publishing the time */
|
||||
printf("%s is ready to begin publishing the time.\n", argv[0]);
|
||||
printf("Press ENTER to publish the current time.\n");
|
||||
printf("Press CTRL-D (or any other key) to exit.\n\n");
|
||||
while(fgetc(stdin) == '\n') {
|
||||
/* get the current time */
|
||||
time_t timer;
|
||||
time(&timer);
|
||||
struct tm* tm_info = localtime(&timer);
|
||||
char timebuf[26];
|
||||
strftime(timebuf, 26, "%Y-%m-%d %H:%M:%S", tm_info);
|
||||
|
||||
/* print a message */
|
||||
char application_message[256];
|
||||
snprintf(application_message, sizeof(application_message), "The time is %s", timebuf);
|
||||
printf("%s published : \"%s\"", argv[0], application_message);
|
||||
|
||||
/* publish the time */
|
||||
mqtt_publish(&client, topic, application_message, strlen(application_message) + 1, MQTT_PUBLISH_QOS_2);
|
||||
|
||||
/* check for errors */
|
||||
if (client.error != MQTT_OK) {
|
||||
fprintf(stderr, "error: %s\n", mqtt_error_str(client.error));
|
||||
exit_example(EXIT_FAILURE, sockfd, &client_daemon);
|
||||
}
|
||||
}
|
||||
|
||||
/* disconnect */
|
||||
printf("\n%s disconnecting from %s\n", argv[0], addr);
|
||||
sleep(1);
|
||||
|
||||
/* exit */
|
||||
exit_example(EXIT_SUCCESS, sockfd, &client_daemon);
|
||||
}
|
||||
|
||||
void exit_example(int status, BIO* sockfd, pthread_t *client_daemon)
|
||||
{
|
||||
if (sockfd != NULL) BIO_free_all(sockfd);
|
||||
if (client_daemon != NULL) pthread_cancel(*client_daemon);
|
||||
exit(status);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void publish_callback(void** unused, struct mqtt_response_publish *published)
|
||||
{
|
||||
/* not used in this example */
|
||||
}
|
||||
|
||||
void* client_refresher(void* client)
|
||||
{
|
||||
while(1)
|
||||
{
|
||||
mqtt_sync((struct mqtt_client*) client);
|
||||
usleep(100000U);
|
||||
}
|
||||
return NULL;
|
||||
}
|
|
@ -0,0 +1,163 @@
|
|||
|
||||
/**
|
||||
* @file
|
||||
*/
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <mqtt.h>
|
||||
#include "templates/mbedtls_sockets.h"
|
||||
|
||||
|
||||
/**
|
||||
* @brief The function that would be called whenever a PUBLISH is received.
|
||||
*
|
||||
* @note This function is not used in this example.
|
||||
*/
|
||||
void publish_callback(void** unused, struct mqtt_response_publish *published);
|
||||
|
||||
/**
|
||||
* @brief The client's refresher. This function triggers back-end routines to
|
||||
* handle ingress/egress traffic to the broker.
|
||||
*
|
||||
* @note All this function needs to do is call \ref __mqtt_recv and
|
||||
* \ref __mqtt_send every so often. I've picked 100 ms meaning that
|
||||
* client ingress/egress traffic will be handled every 100 ms.
|
||||
*/
|
||||
void* client_refresher(void* client);
|
||||
|
||||
/**
|
||||
* @brief Safelty closes the \p sockfd and cancels the \p client_daemon before \c exit.
|
||||
*/
|
||||
void exit_example(int status, mqtt_pal_socket_handle sockfd, pthread_t *client_daemon);
|
||||
|
||||
/**
|
||||
* A simple program to that publishes the current time whenever ENTER is pressed.
|
||||
*/
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
const char* addr;
|
||||
const char* port;
|
||||
const char* topic;
|
||||
const char* ca_file;
|
||||
|
||||
struct mbedtls_context ctx;
|
||||
mqtt_pal_socket_handle sockfd;
|
||||
|
||||
if (argc > 1) {
|
||||
ca_file = argv[1];
|
||||
} else {
|
||||
printf("error: path to the CA certificate to use\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* get address (argv[2] if present) */
|
||||
if (argc > 2) {
|
||||
addr = argv[2];
|
||||
} else {
|
||||
addr = "test.mosquitto.org";
|
||||
}
|
||||
|
||||
/* get port number (argv[3] if present) */
|
||||
if (argc > 3) {
|
||||
port = argv[3];
|
||||
} else {
|
||||
port = "8883";
|
||||
}
|
||||
|
||||
/* get the topic name to publish */
|
||||
if (argc > 4) {
|
||||
topic = argv[4];
|
||||
} else {
|
||||
topic = "datetime";
|
||||
}
|
||||
|
||||
/* open the non-blocking TCP socket (connecting to the broker) */
|
||||
open_nb_socket(&ctx, addr, port, ca_file);
|
||||
sockfd = &ctx.ssl_ctx;
|
||||
|
||||
if (sockfd == NULL) {
|
||||
exit_example(EXIT_FAILURE, sockfd, NULL);
|
||||
}
|
||||
|
||||
/* setup a client */
|
||||
struct mqtt_client client;
|
||||
uint8_t sendbuf[2048]; /* sendbuf should be large enough to hold multiple whole mqtt messages */
|
||||
uint8_t recvbuf[1024]; /* recvbuf should be large enough any whole mqtt message expected to be received */
|
||||
mqtt_init(&client, sockfd, sendbuf, sizeof(sendbuf), recvbuf, sizeof(recvbuf), publish_callback);
|
||||
mqtt_connect(&client, "publishing_client", NULL, NULL, 0, NULL, NULL, 0, 400);
|
||||
|
||||
/* check that we don't have any errors */
|
||||
if (client.error != MQTT_OK) {
|
||||
fprintf(stderr, "error: %s\n", mqtt_error_str(client.error));
|
||||
exit_example(EXIT_FAILURE, sockfd, NULL);
|
||||
}
|
||||
|
||||
/* start a thread to refresh the client (handle egress and ingree client traffic) */
|
||||
pthread_t client_daemon;
|
||||
if(pthread_create(&client_daemon, NULL, client_refresher, &client)) {
|
||||
fprintf(stderr, "Failed to start client daemon.\n");
|
||||
exit_example(EXIT_FAILURE, sockfd, NULL);
|
||||
|
||||
}
|
||||
|
||||
/* start publishing the time */
|
||||
printf("%s is ready to begin publishing the time.\n", argv[0]);
|
||||
printf("Press ENTER to publish the current time.\n");
|
||||
printf("Press CTRL-D (or any other key) to exit.\n\n");
|
||||
while(fgetc(stdin) == '\n') {
|
||||
/* get the current time */
|
||||
time_t timer;
|
||||
time(&timer);
|
||||
struct tm* tm_info = localtime(&timer);
|
||||
char timebuf[26];
|
||||
strftime(timebuf, 26, "%Y-%m-%d %H:%M:%S", tm_info);
|
||||
|
||||
/* print a message */
|
||||
char application_message[256];
|
||||
snprintf(application_message, sizeof(application_message), "The time is %s", timebuf);
|
||||
printf("%s published : \"%s\"", argv[0], application_message);
|
||||
|
||||
/* publish the time */
|
||||
mqtt_publish(&client, topic, application_message, strlen(application_message) + 1, MQTT_PUBLISH_QOS_2);
|
||||
|
||||
/* check for errors */
|
||||
if (client.error != MQTT_OK) {
|
||||
fprintf(stderr, "error: %s\n", mqtt_error_str(client.error));
|
||||
exit_example(EXIT_FAILURE, sockfd, &client_daemon);
|
||||
}
|
||||
}
|
||||
|
||||
/* disconnect */
|
||||
printf("\n%s disconnecting from %s\n", argv[0], addr);
|
||||
sleep(1);
|
||||
|
||||
/* exit */
|
||||
exit_example(EXIT_SUCCESS, sockfd, &client_daemon);
|
||||
}
|
||||
|
||||
void exit_example(int status, mqtt_pal_socket_handle sockfd, pthread_t *client_daemon)
|
||||
{
|
||||
if (client_daemon != NULL) pthread_cancel(*client_daemon);
|
||||
mbedtls_ssl_free(sockfd);
|
||||
/* XXX free the rest of contexts */
|
||||
exit(status);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void publish_callback(void** unused, struct mqtt_response_publish *published)
|
||||
{
|
||||
/* not used in this example */
|
||||
}
|
||||
|
||||
void* client_refresher(void* client)
|
||||
{
|
||||
while(1)
|
||||
{
|
||||
mqtt_sync((struct mqtt_client*) client);
|
||||
usleep(100000U);
|
||||
}
|
||||
return NULL;
|
||||
}
|
|
@ -0,0 +1,167 @@
|
|||
|
||||
/**
|
||||
* @file
|
||||
*/
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <mqtt.h>
|
||||
#include "templates/openssl_sockets.h"
|
||||
|
||||
|
||||
/**
|
||||
* @brief The function that would be called whenever a PUBLISH is received.
|
||||
*
|
||||
* @note This function is not used in this example.
|
||||
*/
|
||||
void publish_callback(void** unused, struct mqtt_response_publish *published);
|
||||
|
||||
/**
|
||||
* @brief The client's refresher. This function triggers back-end routines to
|
||||
* handle ingress/egress traffic to the broker.
|
||||
*
|
||||
* @note All this function needs to do is call \ref __mqtt_recv and
|
||||
* \ref __mqtt_send every so often. I've picked 100 ms meaning that
|
||||
* client ingress/egress traffic will be handled every 100 ms.
|
||||
*/
|
||||
void* client_refresher(void* client);
|
||||
|
||||
/**
|
||||
* @brief Safelty closes the \p sockfd and cancels the \p client_daemon before \c exit.
|
||||
*/
|
||||
void exit_example(int status, BIO* sockfd, pthread_t *client_daemon);
|
||||
|
||||
/**
|
||||
* A simple program to that publishes the current time whenever ENTER is pressed.
|
||||
*/
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
const char* addr;
|
||||
const char* port;
|
||||
const char* topic;
|
||||
const char* ca_file;
|
||||
|
||||
/* Load OpenSSL */
|
||||
SSL_load_error_strings();
|
||||
ERR_load_BIO_strings();
|
||||
OpenSSL_add_all_algorithms();
|
||||
SSL_library_init();
|
||||
|
||||
SSL_CTX* ssl_ctx;
|
||||
BIO* sockfd;
|
||||
|
||||
if (argc > 1) {
|
||||
ca_file = argv[1];
|
||||
} else {
|
||||
printf("error: path to the CA certificate to use\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* get address (argv[2] if present) */
|
||||
if (argc > 2) {
|
||||
addr = argv[2];
|
||||
} else {
|
||||
addr = "test.mosquitto.org";
|
||||
}
|
||||
|
||||
/* get port number (argv[3] if present) */
|
||||
if (argc > 3) {
|
||||
port = argv[3];
|
||||
} else {
|
||||
port = "8883";
|
||||
}
|
||||
|
||||
/* get the topic name to publish */
|
||||
if (argc > 4) {
|
||||
topic = argv[4];
|
||||
} else {
|
||||
topic = "datetime";
|
||||
}
|
||||
|
||||
/* open the non-blocking TCP socket (connecting to the broker) */
|
||||
open_nb_socket(&sockfd, &ssl_ctx, addr, port, ca_file, NULL);
|
||||
|
||||
if (sockfd == NULL) {
|
||||
exit_example(EXIT_FAILURE, sockfd, NULL);
|
||||
}
|
||||
|
||||
/* setup a client */
|
||||
struct mqtt_client client;
|
||||
uint8_t sendbuf[2048]; /* sendbuf should be large enough to hold multiple whole mqtt messages */
|
||||
uint8_t recvbuf[1024]; /* recvbuf should be large enough any whole mqtt message expected to be received */
|
||||
mqtt_init(&client, sockfd, sendbuf, sizeof(sendbuf), recvbuf, sizeof(recvbuf), publish_callback);
|
||||
mqtt_connect(&client, "publishing_client", NULL, NULL, 0, NULL, NULL, 0, 400);
|
||||
|
||||
/* check that we don't have any errors */
|
||||
if (client.error != MQTT_OK) {
|
||||
fprintf(stderr, "error: %s\n", mqtt_error_str(client.error));
|
||||
exit_example(EXIT_FAILURE, sockfd, NULL);
|
||||
}
|
||||
|
||||
/* start a thread to refresh the client (handle egress and ingree client traffic) */
|
||||
pthread_t client_daemon;
|
||||
if(pthread_create(&client_daemon, NULL, client_refresher, &client)) {
|
||||
fprintf(stderr, "Failed to start client daemon.\n");
|
||||
exit_example(EXIT_FAILURE, sockfd, NULL);
|
||||
|
||||
}
|
||||
|
||||
/* start publishing the time */
|
||||
printf("%s is ready to begin publishing the time.\n", argv[0]);
|
||||
printf("Press ENTER to publish the current time.\n");
|
||||
printf("Press CTRL-D (or any other key) to exit.\n\n");
|
||||
while(fgetc(stdin) == '\n') {
|
||||
/* get the current time */
|
||||
time_t timer;
|
||||
time(&timer);
|
||||
struct tm* tm_info = localtime(&timer);
|
||||
char timebuf[26];
|
||||
strftime(timebuf, 26, "%Y-%m-%d %H:%M:%S", tm_info);
|
||||
|
||||
/* print a message */
|
||||
char application_message[256];
|
||||
snprintf(application_message, sizeof(application_message), "The time is %s", timebuf);
|
||||
printf("%s published : \"%s\"", argv[0], application_message);
|
||||
|
||||
/* publish the time */
|
||||
mqtt_publish(&client, topic, application_message, strlen(application_message) + 1, MQTT_PUBLISH_QOS_2);
|
||||
|
||||
/* check for errors */
|
||||
if (client.error != MQTT_OK) {
|
||||
fprintf(stderr, "error: %s\n", mqtt_error_str(client.error));
|
||||
exit_example(EXIT_FAILURE, sockfd, &client_daemon);
|
||||
}
|
||||
}
|
||||
|
||||
/* disconnect */
|
||||
printf("\n%s disconnecting from %s\n", argv[0], addr);
|
||||
sleep(1);
|
||||
|
||||
/* exit */
|
||||
exit_example(EXIT_SUCCESS, sockfd, &client_daemon);
|
||||
}
|
||||
|
||||
void exit_example(int status, BIO* sockfd, pthread_t *client_daemon)
|
||||
{
|
||||
if (sockfd != NULL) BIO_free_all(sockfd);
|
||||
if (client_daemon != NULL) pthread_cancel(*client_daemon);
|
||||
exit(status);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void publish_callback(void** unused, struct mqtt_response_publish *published)
|
||||
{
|
||||
/* not used in this example */
|
||||
}
|
||||
|
||||
void* client_refresher(void* client)
|
||||
{
|
||||
while(1)
|
||||
{
|
||||
mqtt_sync((struct mqtt_client*) client);
|
||||
usleep(100000U);
|
||||
}
|
||||
return NULL;
|
||||
}
|
|
@ -0,0 +1,199 @@
|
|||
|
||||
/**
|
||||
* @file
|
||||
* A simple subscriber program that performs automatic reconnections.
|
||||
*/
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <mqtt.h>
|
||||
#include "templates/posix_sockets.h"
|
||||
|
||||
/**
|
||||
* @brief A structure that I will use to keep track of some data needed
|
||||
* to setup the connection to the broker.
|
||||
*
|
||||
* An instance of this struct will be created in my \c main(). Then, whenever
|
||||
* \ref reconnect_client is called, this instance will be passed.
|
||||
*/
|
||||
struct reconnect_state_t {
|
||||
const char* hostname;
|
||||
const char* port;
|
||||
const char* topic;
|
||||
uint8_t* sendbuf;
|
||||
size_t sendbufsz;
|
||||
uint8_t* recvbuf;
|
||||
size_t recvbufsz;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief My reconnect callback. It will reestablish the connection whenever
|
||||
* an error occurs.
|
||||
*/
|
||||
void reconnect_client(struct mqtt_client* client, void **reconnect_state_vptr);
|
||||
|
||||
/**
|
||||
* @brief The function will be called whenever a PUBLISH message is received.
|
||||
*/
|
||||
void publish_callback(void** unused, struct mqtt_response_publish *published);
|
||||
|
||||
/**
|
||||
* @brief The client's refresher. This function triggers back-end routines to
|
||||
* handle ingress/egress traffic to the broker.
|
||||
*
|
||||
* @note All this function needs to do is call \ref __mqtt_recv and
|
||||
* \ref __mqtt_send every so often. I've picked 100 ms meaning that
|
||||
* client ingress/egress traffic will be handled every 100 ms.
|
||||
*/
|
||||
void* client_refresher(void* client);
|
||||
|
||||
/**
|
||||
* @brief Safelty closes the \p sockfd and cancels the \p client_daemon before \c exit.
|
||||
*/
|
||||
void exit_example(int status, int sockfd, pthread_t *client_daemon);
|
||||
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
const char* addr;
|
||||
const char* port;
|
||||
const char* topic;
|
||||
|
||||
/* get address (argv[1] if present) */
|
||||
if (argc > 1) {
|
||||
addr = argv[1];
|
||||
} else {
|
||||
addr = "test.mosquitto.org";
|
||||
}
|
||||
|
||||
/* get port number (argv[2] if present) */
|
||||
if (argc > 2) {
|
||||
port = argv[2];
|
||||
} else {
|
||||
port = "1883";
|
||||
}
|
||||
|
||||
/* get the topic name to publish */
|
||||
if (argc > 3) {
|
||||
topic = argv[3];
|
||||
} else {
|
||||
topic = "datetime";
|
||||
}
|
||||
|
||||
/* build the reconnect_state structure which will be passed to reconnect */
|
||||
struct reconnect_state_t reconnect_state;
|
||||
reconnect_state.hostname = addr;
|
||||
reconnect_state.port = port;
|
||||
reconnect_state.topic = topic;
|
||||
uint8_t sendbuf[2048];
|
||||
uint8_t recvbuf[1024];
|
||||
reconnect_state.sendbuf = sendbuf;
|
||||
reconnect_state.sendbufsz = sizeof(sendbuf);
|
||||
reconnect_state.recvbuf = recvbuf;
|
||||
reconnect_state.recvbufsz = sizeof(recvbuf);
|
||||
|
||||
/* setup a client */
|
||||
struct mqtt_client client;
|
||||
|
||||
mqtt_init_reconnect(&client,
|
||||
reconnect_client, &reconnect_state,
|
||||
publish_callback
|
||||
);
|
||||
|
||||
/* start a thread to refresh the client (handle egress and ingree client traffic) */
|
||||
pthread_t client_daemon;
|
||||
if(pthread_create(&client_daemon, NULL, client_refresher, &client)) {
|
||||
fprintf(stderr, "Failed to start client daemon.\n");
|
||||
exit_example(EXIT_FAILURE, -1, NULL);
|
||||
|
||||
}
|
||||
|
||||
/* start publishing the time */
|
||||
printf("%s listening for '%s' messages.\n", argv[0], topic);
|
||||
printf("Press ENTER to inject an error.\n");
|
||||
printf("Press CTRL-D to exit.\n\n");
|
||||
|
||||
/* block */
|
||||
while(fgetc(stdin) != EOF) {
|
||||
printf("Injecting error: \"MQTT_ERROR_SOCKET_ERROR\"\n");
|
||||
client.error = MQTT_ERROR_SOCKET_ERROR;
|
||||
}
|
||||
|
||||
/* disconnect */
|
||||
printf("\n%s disconnecting from %s\n", argv[0], addr);
|
||||
sleep(1);
|
||||
|
||||
/* exit */
|
||||
exit_example(EXIT_SUCCESS, client.socketfd, &client_daemon);
|
||||
}
|
||||
|
||||
void reconnect_client(struct mqtt_client* client, void **reconnect_state_vptr)
|
||||
{
|
||||
struct reconnect_state_t *reconnect_state = *((struct reconnect_state_t**) reconnect_state_vptr);
|
||||
|
||||
/* Close the clients socket if this isn't the initial reconnect call */
|
||||
if (client->error != MQTT_ERROR_INITIAL_RECONNECT) {
|
||||
close(client->socketfd);
|
||||
}
|
||||
|
||||
/* Perform error handling here. */
|
||||
if (client->error != MQTT_ERROR_INITIAL_RECONNECT) {
|
||||
printf("reconnect_client: called while client was in error state \"%s\"\n",
|
||||
mqtt_error_str(client->error)
|
||||
);
|
||||
}
|
||||
|
||||
/* Open a new socket. */
|
||||
int sockfd = open_nb_socket(reconnect_state->hostname, reconnect_state->port);
|
||||
if (sockfd == -1) {
|
||||
perror("Failed to open socket: ");
|
||||
exit_example(EXIT_FAILURE, sockfd, NULL);
|
||||
}
|
||||
|
||||
/* Reinitialize the client. */
|
||||
mqtt_reinit(client, sockfd,
|
||||
reconnect_state->sendbuf, reconnect_state->sendbufsz,
|
||||
reconnect_state->recvbuf, reconnect_state->recvbufsz
|
||||
);
|
||||
|
||||
/* Create an anonymous session */
|
||||
const char* client_id = NULL;
|
||||
/* Ensure we have a clean session */
|
||||
uint8_t connect_flags = MQTT_CONNECT_CLEAN_SESSION;
|
||||
/* Send connection request to the broker. */
|
||||
mqtt_connect(client, client_id, NULL, NULL, 0, NULL, NULL, connect_flags, 400);
|
||||
|
||||
/* Subscribe to the topic. */
|
||||
mqtt_subscribe(client, reconnect_state->topic, 0);
|
||||
}
|
||||
|
||||
void exit_example(int status, int sockfd, pthread_t *client_daemon)
|
||||
{
|
||||
if (sockfd != -1) close(sockfd);
|
||||
if (client_daemon != NULL) pthread_cancel(*client_daemon);
|
||||
exit(status);
|
||||
}
|
||||
|
||||
void publish_callback(void** unused, struct mqtt_response_publish *published)
|
||||
{
|
||||
/* note that published->topic_name is NOT null-terminated (here we'll change it to a c-string) */
|
||||
char* topic_name = (char*) malloc(published->topic_name_size + 1);
|
||||
memcpy(topic_name, published->topic_name, published->topic_name_size);
|
||||
topic_name[published->topic_name_size] = '\0';
|
||||
|
||||
printf("Received publish('%s'): %s\n", topic_name, (const char*) published->application_message);
|
||||
|
||||
free(topic_name);
|
||||
}
|
||||
|
||||
void* client_refresher(void* client)
|
||||
{
|
||||
while(1)
|
||||
{
|
||||
mqtt_sync((struct mqtt_client*) client);
|
||||
usleep(100000U);
|
||||
}
|
||||
return NULL;
|
||||
}
|
|
@ -0,0 +1,157 @@
|
|||
|
||||
/**
|
||||
* @file
|
||||
* A simple program to that publishes the current time whenever ENTER is pressed.
|
||||
*/
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <mqtt.h>
|
||||
#include "templates/posix_sockets.h"
|
||||
|
||||
|
||||
/**
|
||||
* @brief The function that would be called whenever a PUBLISH is received.
|
||||
*
|
||||
* @note This function is not used in this example.
|
||||
*/
|
||||
void publish_callback(void** unused, struct mqtt_response_publish *published);
|
||||
|
||||
/**
|
||||
* @brief The client's refresher. This function triggers back-end routines to
|
||||
* handle ingress/egress traffic to the broker.
|
||||
*
|
||||
* @note All this function needs to do is call \ref __mqtt_recv and
|
||||
* \ref __mqtt_send every so often. I've picked 100 ms meaning that
|
||||
* client ingress/egress traffic will be handled every 100 ms.
|
||||
*/
|
||||
void* client_refresher(void* client);
|
||||
|
||||
/**
|
||||
* @brief Safelty closes the \p sockfd and cancels the \p client_daemon before \c exit.
|
||||
*/
|
||||
void exit_example(int status, int sockfd, pthread_t *client_daemon);
|
||||
|
||||
/**
|
||||
* A simple program to that publishes the current time whenever ENTER is pressed.
|
||||
*/
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
const char* addr;
|
||||
const char* port;
|
||||
const char* topic;
|
||||
|
||||
/* get address (argv[1] if present) */
|
||||
if (argc > 1) {
|
||||
addr = argv[1];
|
||||
} else {
|
||||
addr = "test.mosquitto.org";
|
||||
}
|
||||
|
||||
/* get port number (argv[2] if present) */
|
||||
if (argc > 2) {
|
||||
port = argv[2];
|
||||
} else {
|
||||
port = "1883";
|
||||
}
|
||||
|
||||
/* get the topic name to publish */
|
||||
if (argc > 3) {
|
||||
topic = argv[3];
|
||||
} else {
|
||||
topic = "datetime";
|
||||
}
|
||||
|
||||
/* open the non-blocking TCP socket (connecting to the broker) */
|
||||
int sockfd = open_nb_socket(addr, port);
|
||||
|
||||
if (sockfd == -1) {
|
||||
perror("Failed to open socket: ");
|
||||
exit_example(EXIT_FAILURE, sockfd, NULL);
|
||||
}
|
||||
|
||||
/* setup a client */
|
||||
struct mqtt_client client;
|
||||
uint8_t sendbuf[2048]; /* sendbuf should be large enough to hold multiple whole mqtt messages */
|
||||
uint8_t recvbuf[1024]; /* recvbuf should be large enough any whole mqtt message expected to be received */
|
||||
mqtt_init(&client, sockfd, sendbuf, sizeof(sendbuf), recvbuf, sizeof(recvbuf), publish_callback);
|
||||
/* Create an anonymous session */
|
||||
const char* client_id = NULL;
|
||||
/* Ensure we have a clean session */
|
||||
uint8_t connect_flags = MQTT_CONNECT_CLEAN_SESSION;
|
||||
/* Send connection request to the broker. */
|
||||
mqtt_connect(&client, client_id, NULL, NULL, 0, NULL, NULL, connect_flags, 400);
|
||||
|
||||
/* check that we don't have any errors */
|
||||
if (client.error != MQTT_OK) {
|
||||
fprintf(stderr, "error: %s\n", mqtt_error_str(client.error));
|
||||
exit_example(EXIT_FAILURE, sockfd, NULL);
|
||||
}
|
||||
|
||||
/* start a thread to refresh the client (handle egress and ingree client traffic) */
|
||||
pthread_t client_daemon;
|
||||
if(pthread_create(&client_daemon, NULL, client_refresher, &client)) {
|
||||
fprintf(stderr, "Failed to start client daemon.\n");
|
||||
exit_example(EXIT_FAILURE, sockfd, NULL);
|
||||
|
||||
}
|
||||
|
||||
/* start publishing the time */
|
||||
printf("%s is ready to begin publishing the time.\n", argv[0]);
|
||||
printf("Press ENTER to publish the current time.\n");
|
||||
printf("Press CTRL-D (or any other key) to exit.\n\n");
|
||||
while(fgetc(stdin) == '\n') {
|
||||
/* get the current time */
|
||||
time_t timer;
|
||||
time(&timer);
|
||||
struct tm* tm_info = localtime(&timer);
|
||||
char timebuf[26];
|
||||
strftime(timebuf, 26, "%Y-%m-%d %H:%M:%S", tm_info);
|
||||
|
||||
/* print a message */
|
||||
char application_message[256];
|
||||
snprintf(application_message, sizeof(application_message), "The time is %s", timebuf);
|
||||
printf("%s published : \"%s\"", argv[0], application_message);
|
||||
|
||||
/* publish the time */
|
||||
mqtt_publish(&client, topic, application_message, strlen(application_message) + 1, MQTT_PUBLISH_QOS_0);
|
||||
|
||||
/* check for errors */
|
||||
if (client.error != MQTT_OK) {
|
||||
fprintf(stderr, "error: %s\n", mqtt_error_str(client.error));
|
||||
exit_example(EXIT_FAILURE, sockfd, &client_daemon);
|
||||
}
|
||||
}
|
||||
|
||||
/* disconnect */
|
||||
printf("\n%s disconnecting from %s\n", argv[0], addr);
|
||||
sleep(1);
|
||||
|
||||
/* exit */
|
||||
exit_example(EXIT_SUCCESS, sockfd, &client_daemon);
|
||||
}
|
||||
|
||||
void exit_example(int status, int sockfd, pthread_t *client_daemon)
|
||||
{
|
||||
if (sockfd != -1) close(sockfd);
|
||||
if (client_daemon != NULL) pthread_cancel(*client_daemon);
|
||||
exit(status);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void publish_callback(void** unused, struct mqtt_response_publish *published)
|
||||
{
|
||||
/* not used in this example */
|
||||
}
|
||||
|
||||
void* client_refresher(void* client)
|
||||
{
|
||||
while(1)
|
||||
{
|
||||
mqtt_sync((struct mqtt_client*) client);
|
||||
usleep(100000U);
|
||||
}
|
||||
return NULL;
|
||||
}
|
|
@ -0,0 +1,142 @@
|
|||
|
||||
/**
|
||||
* @file
|
||||
* A simple program that subscribes to a topic.
|
||||
*/
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <mqtt.h>
|
||||
#include "templates/posix_sockets.h"
|
||||
|
||||
|
||||
/**
|
||||
* @brief The function will be called whenever a PUBLISH message is received.
|
||||
*/
|
||||
void publish_callback(void** unused, struct mqtt_response_publish *published);
|
||||
|
||||
/**
|
||||
* @brief The client's refresher. This function triggers back-end routines to
|
||||
* handle ingress/egress traffic to the broker.
|
||||
*
|
||||
* @note All this function needs to do is call \ref __mqtt_recv and
|
||||
* \ref __mqtt_send every so often. I've picked 100 ms meaning that
|
||||
* client ingress/egress traffic will be handled every 100 ms.
|
||||
*/
|
||||
void* client_refresher(void* client);
|
||||
|
||||
/**
|
||||
* @brief Safelty closes the \p sockfd and cancels the \p client_daemon before \c exit.
|
||||
*/
|
||||
void exit_example(int status, int sockfd, pthread_t *client_daemon);
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
const char* addr;
|
||||
const char* port;
|
||||
const char* topic;
|
||||
|
||||
/* get address (argv[1] if present) */
|
||||
if (argc > 1) {
|
||||
addr = argv[1];
|
||||
} else {
|
||||
addr = "test.mosquitto.org";
|
||||
}
|
||||
|
||||
/* get port number (argv[2] if present) */
|
||||
if (argc > 2) {
|
||||
port = argv[2];
|
||||
} else {
|
||||
port = "1883";
|
||||
}
|
||||
|
||||
/* get the topic name to publish */
|
||||
if (argc > 3) {
|
||||
topic = argv[3];
|
||||
} else {
|
||||
topic = "datetime";
|
||||
}
|
||||
|
||||
/* open the non-blocking TCP socket (connecting to the broker) */
|
||||
int sockfd = open_nb_socket(addr, port);
|
||||
|
||||
if (sockfd == -1) {
|
||||
perror("Failed to open socket: ");
|
||||
exit_example(EXIT_FAILURE, sockfd, NULL);
|
||||
}
|
||||
|
||||
/* setup a client */
|
||||
struct mqtt_client client;
|
||||
uint8_t sendbuf[2048]; /* sendbuf should be large enough to hold multiple whole mqtt messages */
|
||||
uint8_t recvbuf[1024]; /* recvbuf should be large enough any whole mqtt message expected to be received */
|
||||
mqtt_init(&client, sockfd, sendbuf, sizeof(sendbuf), recvbuf, sizeof(recvbuf), publish_callback);
|
||||
/* Create an anonymous session */
|
||||
const char* client_id = NULL;
|
||||
/* Ensure we have a clean session */
|
||||
uint8_t connect_flags = MQTT_CONNECT_CLEAN_SESSION;
|
||||
/* Send connection request to the broker. */
|
||||
mqtt_connect(&client, client_id, NULL, NULL, 0, NULL, NULL, connect_flags, 400);
|
||||
|
||||
/* check that we don't have any errors */
|
||||
if (client.error != MQTT_OK) {
|
||||
fprintf(stderr, "error: %s\n", mqtt_error_str(client.error));
|
||||
exit_example(EXIT_FAILURE, sockfd, NULL);
|
||||
}
|
||||
|
||||
/* start a thread to refresh the client (handle egress and ingree client traffic) */
|
||||
pthread_t client_daemon;
|
||||
if(pthread_create(&client_daemon, NULL, client_refresher, &client)) {
|
||||
fprintf(stderr, "Failed to start client daemon.\n");
|
||||
exit_example(EXIT_FAILURE, sockfd, NULL);
|
||||
|
||||
}
|
||||
|
||||
/* subscribe */
|
||||
mqtt_subscribe(&client, topic, 0);
|
||||
|
||||
/* start publishing the time */
|
||||
printf("%s listening for '%s' messages.\n", argv[0], topic);
|
||||
printf("Press CTRL-D to exit.\n\n");
|
||||
|
||||
/* block */
|
||||
while(fgetc(stdin) != EOF);
|
||||
|
||||
/* disconnect */
|
||||
printf("\n%s disconnecting from %s\n", argv[0], addr);
|
||||
sleep(1);
|
||||
|
||||
/* exit */
|
||||
exit_example(EXIT_SUCCESS, sockfd, &client_daemon);
|
||||
}
|
||||
|
||||
void exit_example(int status, int sockfd, pthread_t *client_daemon)
|
||||
{
|
||||
if (sockfd != -1) close(sockfd);
|
||||
if (client_daemon != NULL) pthread_cancel(*client_daemon);
|
||||
exit(status);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void publish_callback(void** unused, struct mqtt_response_publish *published)
|
||||
{
|
||||
/* note that published->topic_name is NOT null-terminated (here we'll change it to a c-string) */
|
||||
char* topic_name = (char*) malloc(published->topic_name_size + 1);
|
||||
memcpy(topic_name, published->topic_name, published->topic_name_size);
|
||||
topic_name[published->topic_name_size] = '\0';
|
||||
|
||||
printf("Received publish('%s'): %s\n", topic_name, (const char*) published->application_message);
|
||||
|
||||
free(topic_name);
|
||||
}
|
||||
|
||||
void* client_refresher(void* client)
|
||||
{
|
||||
while(1)
|
||||
{
|
||||
mqtt_sync((struct mqtt_client*) client);
|
||||
usleep(100000U);
|
||||
}
|
||||
return NULL;
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
#ifndef __BIO_SOCKET_TEMPLATE_H__
|
||||
#define __BIO_SOCKET_TEMPLATE_H__
|
||||
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/err.h>
|
||||
|
||||
/*
|
||||
A template for opening a non-blocking BIO socket.
|
||||
*/
|
||||
BIO* open_nb_socket(const char* addr, const char* port) {
|
||||
BIO* bio = BIO_new_connect(addr);
|
||||
BIO_set_nbio(bio, 1);
|
||||
BIO_set_conn_port(bio, port);
|
||||
|
||||
/* timeout after 10 seconds */
|
||||
int start_time = time(NULL);
|
||||
while(BIO_do_connect(bio) == 0 && (int)time(NULL) - start_time < 10);
|
||||
|
||||
if (BIO_do_connect(bio) <= 0) {
|
||||
fprintf(stderr, "Failed to open socket: BIO_do_connect returned <= 0\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return bio;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,145 @@
|
|||
#ifndef __MBEDTLS_SOCKET_TEMPLATE_H__
|
||||
#define __MBEDTLS_SOCKET_TEMPLATE_H__
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <mbedtls/error.h>
|
||||
#include <mbedtls/entropy.h>
|
||||
#include <mbedtls/ctr_drbg.h>
|
||||
#include <mbedtls/net_sockets.h>
|
||||
#include <mbedtls/ssl.h>
|
||||
|
||||
#if !defined(MBEDTLS_NET_POLL_READ)
|
||||
/* compat for older mbedtls */
|
||||
#define MBEDTLS_NET_POLL_READ 1
|
||||
#define MBEDTLS_NET_POLL_WRITE 1
|
||||
|
||||
int
|
||||
mbedtls_net_poll(mbedtls_net_context * ctx, uint32_t rw, uint32_t timeout)
|
||||
{
|
||||
/* XXX this is not ideal but good enough for an example */
|
||||
usleep(300);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
struct mbedtls_context {
|
||||
mbedtls_net_context net_ctx;
|
||||
mbedtls_ssl_context ssl_ctx;
|
||||
mbedtls_ssl_config ssl_conf;
|
||||
mbedtls_x509_crt ca_crt;
|
||||
mbedtls_entropy_context entropy;
|
||||
mbedtls_ctr_drbg_context ctr_drbg;
|
||||
};
|
||||
|
||||
void failed(const char *fn, int rv) {
|
||||
char buf[100];
|
||||
mbedtls_strerror(rv, buf, sizeof(buf));
|
||||
printf("%s failed with %x (%s)\n", fn, -rv, buf);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void cert_verify_failed(uint32_t rv) {
|
||||
char buf[512];
|
||||
mbedtls_x509_crt_verify_info(buf, sizeof(buf), "\t", rv);
|
||||
printf("Certificate verification failed (%0" PRIx32 ")\n%s\n", rv, buf);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
A template for opening a non-blocking mbed TLS connection.
|
||||
*/
|
||||
void open_nb_socket(struct mbedtls_context *ctx,
|
||||
const char *hostname,
|
||||
const char *port,
|
||||
const char *ca_file) {
|
||||
const unsigned char *additional = (const unsigned char *)"MQTT-C";
|
||||
size_t additional_len = 6;
|
||||
int rv;
|
||||
|
||||
mbedtls_net_context *net_ctx = &ctx->net_ctx;
|
||||
mbedtls_ssl_context *ssl_ctx = &ctx->ssl_ctx;
|
||||
mbedtls_ssl_config *ssl_conf = &ctx->ssl_conf;
|
||||
mbedtls_x509_crt *ca_crt = &ctx->ca_crt;
|
||||
mbedtls_entropy_context *entropy = &ctx->entropy;
|
||||
mbedtls_ctr_drbg_context *ctr_drbg = &ctx->ctr_drbg;
|
||||
|
||||
mbedtls_entropy_init(entropy);
|
||||
mbedtls_ctr_drbg_init(ctr_drbg);
|
||||
rv = mbedtls_ctr_drbg_seed(ctr_drbg, mbedtls_entropy_func, entropy,
|
||||
additional, additional_len);
|
||||
if (rv != 0) {
|
||||
failed("mbedtls_ctr_drbg_seed", rv);
|
||||
}
|
||||
|
||||
mbedtls_x509_crt_init(ca_crt);
|
||||
rv = mbedtls_x509_crt_parse_file(ca_crt, ca_file);
|
||||
if (rv != 0) {
|
||||
failed("mbedtls_x509_crt_parse_file", rv);
|
||||
}
|
||||
|
||||
mbedtls_ssl_config_init(ssl_conf);
|
||||
rv = mbedtls_ssl_config_defaults(ssl_conf, MBEDTLS_SSL_IS_CLIENT,
|
||||
MBEDTLS_SSL_TRANSPORT_STREAM,
|
||||
MBEDTLS_SSL_PRESET_DEFAULT);
|
||||
if (rv != 0) {
|
||||
failed("mbedtls_ssl_config_defaults", rv);
|
||||
}
|
||||
mbedtls_ssl_conf_ca_chain(ssl_conf, ca_crt, NULL);
|
||||
mbedtls_ssl_conf_authmode(ssl_conf, MBEDTLS_SSL_VERIFY_OPTIONAL);
|
||||
mbedtls_ssl_conf_rng(ssl_conf, mbedtls_ctr_drbg_random, ctr_drbg);
|
||||
|
||||
mbedtls_net_init(net_ctx);
|
||||
rv = mbedtls_net_connect(net_ctx, hostname, port, MBEDTLS_NET_PROTO_TCP);
|
||||
if (rv != 0) {
|
||||
failed("mbedtls_net_connect", rv);
|
||||
}
|
||||
rv = mbedtls_net_set_nonblock(net_ctx);
|
||||
if (rv != 0) {
|
||||
failed("mbedtls_net_set_nonblock", rv);
|
||||
}
|
||||
|
||||
mbedtls_ssl_init(ssl_ctx);
|
||||
rv = mbedtls_ssl_setup(ssl_ctx, ssl_conf);
|
||||
if (rv != 0) {
|
||||
failed("mbedtls_ssl_setup", rv);
|
||||
}
|
||||
rv = mbedtls_ssl_set_hostname(ssl_ctx, hostname);
|
||||
if (rv != 0) {
|
||||
failed("mbedtls_ssl_set_hostname", rv);
|
||||
}
|
||||
mbedtls_ssl_set_bio(ssl_ctx, net_ctx,
|
||||
mbedtls_net_send, mbedtls_net_recv, NULL);
|
||||
|
||||
for (;;) {
|
||||
rv = mbedtls_ssl_handshake(ssl_ctx);
|
||||
uint32_t want = 0;
|
||||
if (rv == MBEDTLS_ERR_SSL_WANT_READ) {
|
||||
want |= MBEDTLS_NET_POLL_READ;
|
||||
} else if (rv == MBEDTLS_ERR_SSL_WANT_WRITE) {
|
||||
want |= MBEDTLS_NET_POLL_WRITE;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
rv = mbedtls_net_poll(net_ctx, want, -1);
|
||||
if (rv < 0) {
|
||||
failed("mbedtls_net_poll", rv);
|
||||
}
|
||||
}
|
||||
if (rv != 0) {
|
||||
failed("mbedtls_ssl_handshake", rv);
|
||||
}
|
||||
uint32_t result = mbedtls_ssl_get_verify_result(ssl_ctx);
|
||||
if (result != 0) {
|
||||
if (result == (uint32_t)-1) {
|
||||
failed("mbedtls_ssl_get_verify_result", result);
|
||||
} else {
|
||||
cert_verify_failed(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,52 @@
|
|||
#ifndef __OPENSSL_SOCKET_TEMPLATE_H__
|
||||
#define __OPENSSL_SOCKET_TEMPLATE_H__
|
||||
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/err.h>
|
||||
|
||||
/*
|
||||
A template for opening a non-blocking OpenSSL connection.
|
||||
*/
|
||||
void open_nb_socket(BIO** bio, SSL_CTX** ssl_ctx, const char* addr, const char* port, const char* ca_file, const char* ca_path) {
|
||||
*ssl_ctx = SSL_CTX_new(SSLv23_client_method());
|
||||
SSL* ssl;
|
||||
|
||||
/* load certificate */
|
||||
if (!SSL_CTX_load_verify_locations(*ssl_ctx, ca_file, ca_path)) {
|
||||
printf("error: failed to load certificate\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* open BIO socket */
|
||||
*bio = BIO_new_ssl_connect(*ssl_ctx);
|
||||
BIO_get_ssl(*bio, &ssl);
|
||||
SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
|
||||
BIO_set_conn_hostname(*bio, addr);
|
||||
BIO_set_nbio(*bio, 1);
|
||||
BIO_set_conn_port(*bio, port);
|
||||
|
||||
/* wait for connect with 10 second timeout */
|
||||
int start_time = time(NULL);
|
||||
int do_connect_rv = BIO_do_connect(*bio);
|
||||
while(do_connect_rv <= 0 && BIO_should_retry(*bio) && (int)time(NULL) - start_time < 10) {
|
||||
do_connect_rv = BIO_do_connect(*bio);
|
||||
}
|
||||
if (do_connect_rv <= 0) {
|
||||
printf("error: %s\n", ERR_reason_error_string(ERR_get_error()));
|
||||
BIO_free_all(*bio);
|
||||
SSL_CTX_free(*ssl_ctx);
|
||||
*bio = NULL;
|
||||
*ssl_ctx=NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
/* verify certificate */
|
||||
if (SSL_get_verify_result(ssl) != X509_V_OK) {
|
||||
/* Handle the failed verification */
|
||||
printf("error: x509 certificate verification failed\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,59 @@
|
|||
#ifndef __POSIX_SOCKET_TEMPLATE_H__
|
||||
#define __POSIX_SOCKET_TEMPLATE_H__
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#if !defined(WIN32)
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
#endif
|
||||
#include <fcntl.h>
|
||||
|
||||
/*
|
||||
A template for opening a non-blocking POSIX socket.
|
||||
*/
|
||||
int open_nb_socket(const char* addr, const char* port) {
|
||||
struct addrinfo hints = {0};
|
||||
|
||||
hints.ai_family = AF_UNSPEC; /* IPv4 or IPv6 */
|
||||
hints.ai_socktype = SOCK_STREAM; /* Must be TCP */
|
||||
int sockfd = -1;
|
||||
int rv;
|
||||
struct addrinfo *p, *servinfo;
|
||||
|
||||
/* get address information */
|
||||
rv = getaddrinfo(addr, port, &hints, &servinfo);
|
||||
if(rv != 0) {
|
||||
fprintf(stderr, "Failed to open socket (getaddrinfo): %s\n", gai_strerror(rv));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* open the first possible socket */
|
||||
for(p = servinfo; p != NULL; p = p->ai_next) {
|
||||
sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
|
||||
if (sockfd == -1) continue;
|
||||
|
||||
/* connect to server */
|
||||
rv = connect(sockfd, servinfo->ai_addr, servinfo->ai_addrlen);
|
||||
if(rv == -1) continue;
|
||||
break;
|
||||
}
|
||||
|
||||
/* free servinfo */
|
||||
freeaddrinfo(servinfo);
|
||||
|
||||
/* make non-blocking */
|
||||
#if !defined(WIN32)
|
||||
if (sockfd != -1) fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFL) | O_NONBLOCK);
|
||||
#else
|
||||
if (sockfd != INVALID_SOCKET) {
|
||||
int iMode = 1;
|
||||
ioctlsocket(sockfd, FIONBIO, &iMode);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* return the new socket fd */
|
||||
return sockfd;
|
||||
}
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,157 @@
|
|||
#ifndef __MQTT_PAL_H__
|
||||
#define __MQTT_PAL_H__
|
||||
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright(c) 2018 Liam Bindle
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions :
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Includes/supports the types/calls required by the MQTT-C client.
|
||||
*
|
||||
* @note This is the \em only file included in mqtt.h, and mqtt.c. It is therefore
|
||||
* responsible for including/supporting all the required types and calls.
|
||||
*
|
||||
* @defgroup pal Platform abstraction layer
|
||||
* @brief Documentation of the types and calls required to port MQTT-C to a new platform.
|
||||
*
|
||||
* mqtt_pal.h is the \em only header file included in mqtt.c. Therefore, to port MQTT-C to a
|
||||
* new platform the following types, functions, constants, and macros must be defined in
|
||||
* mqtt_pal.h:
|
||||
* - Types:
|
||||
* - \c size_t, \c ssize_t
|
||||
* - \c uint8_t, \c uint16_t, \c uint32_t
|
||||
* - \c va_list
|
||||
* - \c mqtt_pal_time_t : return type of \c MQTT_PAL_TIME()
|
||||
* - \c mqtt_pal_mutex_t : type of the argument that is passed to \c MQTT_PAL_MUTEX_LOCK and
|
||||
* \c MQTT_PAL_MUTEX_RELEASE
|
||||
* - Functions:
|
||||
* - \c memcpy, \c strlen
|
||||
* - \c va_start, \c va_arg, \c va_end
|
||||
* - Constants:
|
||||
* - \c INT_MIN
|
||||
*
|
||||
* Additionally, three macro's are required:
|
||||
* - \c MQTT_PAL_HTONS(s) : host-to-network endian conversion for uint16_t.
|
||||
* - \c MQTT_PAL_NTOHS(s) : network-to-host endian conversion for uint16_t.
|
||||
* - \c MQTT_PAL_TIME() : returns [type: \c mqtt_pal_time_t] current time in seconds.
|
||||
* - \c MQTT_PAL_MUTEX_LOCK(mtx_pointer) : macro that locks the mutex pointed to by \c mtx_pointer.
|
||||
* - \c MQTT_PAL_MUTEX_RELEASE(mtx_pointer) : macro that unlocks the mutex pointed to by
|
||||
* \c mtx_pointer.
|
||||
*
|
||||
* Lastly, \ref mqtt_pal_sendall and \ref mqtt_pal_recvall, must be implemented in mqtt_pal.c
|
||||
* for sending and receiving data using the platforms socket calls.
|
||||
*/
|
||||
|
||||
|
||||
/* UNIX-like platform support */
|
||||
#if defined(__unix__) || defined(__APPLE__)
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <time.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#define MQTT_PAL_HTONS(s) htons(s)
|
||||
#define MQTT_PAL_NTOHS(s) ntohs(s)
|
||||
|
||||
#define MQTT_PAL_TIME() time(NULL)
|
||||
|
||||
typedef time_t mqtt_pal_time_t;
|
||||
typedef pthread_mutex_t mqtt_pal_mutex_t;
|
||||
|
||||
#define MQTT_PAL_MUTEX_INIT(mtx_ptr) pthread_mutex_init(mtx_ptr, NULL)
|
||||
#define MQTT_PAL_MUTEX_LOCK(mtx_ptr) pthread_mutex_lock(mtx_ptr)
|
||||
#define MQTT_PAL_MUTEX_UNLOCK(mtx_ptr) pthread_mutex_unlock(mtx_ptr)
|
||||
|
||||
#ifndef MQTT_USE_CUSTOM_SOCKET_HANDLE
|
||||
#ifdef MQTT_USE_MBEDTLS
|
||||
struct mbedtls_ssl_context;
|
||||
typedef struct mbedtls_ssl_context *mqtt_pal_socket_handle;
|
||||
#elif defined(MQTT_USE_BIO)
|
||||
#include <openssl/bio.h>
|
||||
typedef BIO* mqtt_pal_socket_handle;
|
||||
#else
|
||||
typedef int mqtt_pal_socket_handle;
|
||||
#endif
|
||||
#endif
|
||||
#elif defined(_MSC_VER)
|
||||
#include <limits.h>
|
||||
#include <windows.h>
|
||||
#include <time.h>
|
||||
#include <stdint.h>
|
||||
#include <winsock2.h>
|
||||
|
||||
typedef SSIZE_T ssize_t;
|
||||
#define MQTT_PAL_HTONS(s) htons(s)
|
||||
#define MQTT_PAL_NTOHS(s) ntohs(s)
|
||||
|
||||
#define MQTT_PAL_TIME() time(NULL)
|
||||
|
||||
typedef time_t mqtt_pal_time_t;
|
||||
typedef CRITICAL_SECTION mqtt_pal_mutex_t;
|
||||
|
||||
#define MQTT_PAL_MUTEX_INIT(mtx_ptr) InitializeCriticalSection(mtx_ptr)
|
||||
#define MQTT_PAL_MUTEX_LOCK(mtx_ptr) EnterCriticalSection(mtx_ptr)
|
||||
#define MQTT_PAL_MUTEX_UNLOCK(mtx_ptr) LeaveCriticalSection(mtx_ptr)
|
||||
|
||||
|
||||
#ifndef MQTT_USE_CUSTOM_SOCKET_HANDLE
|
||||
#ifdef MQTT_USE_BIO
|
||||
#include <openssl/bio.h>
|
||||
typedef BIO* mqtt_pal_socket_handle;
|
||||
#else
|
||||
typedef SOCKET mqtt_pal_socket_handle;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Sends all the bytes in a buffer.
|
||||
* @ingroup pal
|
||||
*
|
||||
* @param[in] fd The file-descriptor (or handle) of the socket.
|
||||
* @param[in] buf A pointer to the first byte in the buffer to send.
|
||||
* @param[in] len The number of bytes to send (starting at \p buf).
|
||||
* @param[in] flags Flags which are passed to the underlying socket.
|
||||
*
|
||||
* @returns The number of bytes sent if successful, an \ref MQTTErrors otherwise.
|
||||
*/
|
||||
ssize_t mqtt_pal_sendall(mqtt_pal_socket_handle fd, const void* buf, size_t len, int flags);
|
||||
|
||||
/**
|
||||
* @brief Non-blocking receive all the byte available.
|
||||
* @ingroup pal
|
||||
*
|
||||
* @param[in] fd The file-descriptor (or handle) of the socket.
|
||||
* @param[in] buf A pointer to the receive buffer.
|
||||
* @param[in] bufsz The max number of bytes that can be put into \p buf.
|
||||
* @param[in] flags Flags which are passed to the underlying socket.
|
||||
*
|
||||
* @returns The number of bytes received if successful, an \ref MQTTErrors otherwise.
|
||||
*/
|
||||
ssize_t mqtt_pal_recvall(mqtt_pal_socket_handle fd, void* buf, size_t bufsz, int flags);
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,203 @@
|
|||
/*
|
||||
MIT License
|
||||
|
||||
Copyright(c) 2018 Liam Bindle
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions :
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <mqtt.h>
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Implements @ref mqtt_pal_sendall and @ref mqtt_pal_recvall and
|
||||
* any platform-specific helpers you'd like.
|
||||
* @cond Doxygen_Suppress
|
||||
*/
|
||||
|
||||
|
||||
#ifdef MQTT_USE_MBEDTLS
|
||||
#include <mbedtls/ssl.h>
|
||||
|
||||
ssize_t mqtt_pal_sendall(mqtt_pal_socket_handle fd, const void* buf, size_t len, int flags) {
|
||||
size_t sent = 0;
|
||||
while(sent < len) {
|
||||
int rv = mbedtls_ssl_write(fd, buf + sent, len - sent);
|
||||
if (rv < 0) {
|
||||
if (rv == MBEDTLS_ERR_SSL_WANT_READ ||
|
||||
rv == MBEDTLS_ERR_SSL_WANT_WRITE
|
||||
#if defined(MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS)
|
||||
|| rv == MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS
|
||||
#endif
|
||||
#if defined(MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS)
|
||||
|| rv == MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS
|
||||
#endif
|
||||
) {
|
||||
/* should call mbedtls_ssl_writer later again */
|
||||
break;
|
||||
}
|
||||
return MQTT_ERROR_SOCKET_ERROR;
|
||||
}
|
||||
sent += (size_t) rv;
|
||||
}
|
||||
return sent;
|
||||
}
|
||||
|
||||
ssize_t mqtt_pal_recvall(mqtt_pal_socket_handle fd, void* buf, size_t bufsz, int flags) {
|
||||
const void *const start = buf;
|
||||
int rv;
|
||||
do {
|
||||
rv = mbedtls_ssl_read(fd, buf, bufsz);
|
||||
if (rv < 0) {
|
||||
if (rv == MBEDTLS_ERR_SSL_WANT_READ ||
|
||||
rv == MBEDTLS_ERR_SSL_WANT_WRITE
|
||||
#if defined(MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS)
|
||||
|| rv == MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS
|
||||
#endif
|
||||
#if defined(MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS)
|
||||
|| rv == MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS
|
||||
#endif
|
||||
) {
|
||||
/* should call mbedtls_ssl_read later again */
|
||||
break;
|
||||
}
|
||||
return MQTT_ERROR_SOCKET_ERROR;
|
||||
}
|
||||
buf = (char*)buf + rv;
|
||||
bufsz -= rv;
|
||||
} while (rv > 0);
|
||||
|
||||
return buf - start;
|
||||
}
|
||||
|
||||
#elif defined(MQTT_USE_BIO)
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/err.h>
|
||||
|
||||
ssize_t mqtt_pal_sendall(mqtt_pal_socket_handle fd, const void* buf, size_t len, int flags) {
|
||||
size_t sent = 0;
|
||||
while(sent < len) {
|
||||
int tmp = BIO_write(fd, buf + sent, len - sent);
|
||||
if (tmp > 0) {
|
||||
sent += (size_t) tmp;
|
||||
} else if (tmp <= 0 && !BIO_should_retry(fd)) {
|
||||
return MQTT_ERROR_SOCKET_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return sent;
|
||||
}
|
||||
|
||||
ssize_t mqtt_pal_recvall(mqtt_pal_socket_handle fd, void* buf, size_t bufsz, int flags) {
|
||||
const void *const start = buf;
|
||||
int rv;
|
||||
do {
|
||||
rv = BIO_read(fd, buf, bufsz);
|
||||
if (rv > 0) {
|
||||
/* successfully read bytes from the socket */
|
||||
buf += rv;
|
||||
bufsz -= rv;
|
||||
} else if (!BIO_should_retry(fd)) {
|
||||
/* an error occurred that wasn't "nothing to read". */
|
||||
return MQTT_ERROR_SOCKET_ERROR;
|
||||
}
|
||||
} while (!BIO_should_read(fd));
|
||||
|
||||
return (ssize_t)(buf - start);
|
||||
}
|
||||
|
||||
#elif defined(__unix__) || defined(__APPLE__)
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
ssize_t mqtt_pal_sendall(mqtt_pal_socket_handle fd, const void* buf, size_t len, int flags) {
|
||||
size_t sent = 0;
|
||||
while(sent < len) {
|
||||
ssize_t tmp = send(fd, buf + sent, len - sent, flags);
|
||||
if (tmp < 1) {
|
||||
return MQTT_ERROR_SOCKET_ERROR;
|
||||
}
|
||||
sent += (size_t) tmp;
|
||||
}
|
||||
return sent;
|
||||
}
|
||||
|
||||
ssize_t mqtt_pal_recvall(mqtt_pal_socket_handle fd, void* buf, size_t bufsz, int flags) {
|
||||
const void *const start = buf;
|
||||
ssize_t rv;
|
||||
do {
|
||||
rv = recv(fd, buf, bufsz, flags);
|
||||
if (rv > 0) {
|
||||
/* successfully read bytes from the socket */
|
||||
buf += rv;
|
||||
bufsz -= rv;
|
||||
} else if (rv < 0 && errno != EAGAIN && errno != EWOULDBLOCK) {
|
||||
/* an error occurred that wasn't "nothing to read". */
|
||||
return MQTT_ERROR_SOCKET_ERROR;
|
||||
}
|
||||
} while (rv > 0);
|
||||
|
||||
return buf - start;
|
||||
}
|
||||
|
||||
#elif defined(_MSC_VER)
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
ssize_t mqtt_pal_sendall(mqtt_pal_socket_handle fd, const void* buf, size_t len, int flags) {
|
||||
size_t sent = 0;
|
||||
while(sent < len) {
|
||||
ssize_t tmp = send(fd, (char*)buf + sent, len - sent, flags);
|
||||
if (tmp < 1) {
|
||||
return MQTT_ERROR_SOCKET_ERROR;
|
||||
}
|
||||
sent += (size_t) tmp;
|
||||
}
|
||||
return sent;
|
||||
}
|
||||
|
||||
ssize_t mqtt_pal_recvall(mqtt_pal_socket_handle fd, void* buf, size_t bufsz, int flags) {
|
||||
const char *const start = buf;
|
||||
ssize_t rv;
|
||||
do {
|
||||
rv = recv(fd, buf, bufsz, flags);
|
||||
if (rv > 0) {
|
||||
/* successfully read bytes from the socket */
|
||||
buf = (char*)buf + rv;
|
||||
bufsz -= rv;
|
||||
} else if (rv < 0) {
|
||||
int err = WSAGetLastError();
|
||||
if (err != WSAEWOULDBLOCK) {
|
||||
/* an error occurred that wasn't "nothing to read". */
|
||||
return MQTT_ERROR_SOCKET_ERROR;
|
||||
}
|
||||
}
|
||||
} while (rv > 0);
|
||||
|
||||
return (ssize_t)((char*)buf - start);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#error No PAL!
|
||||
|
||||
#endif
|
||||
|
||||
/** @endcond */
|
File diff suppressed because it is too large
Load Diff
|
@ -63,11 +63,11 @@ TDengine缺省的时间戳是毫秒精度,但通过修改配置参数enableMic
|
|||
| 3 | BIGINT | 8 | 长整型,范围 [-2^63+1, 2^63-1], -2^63用于NULL |
|
||||
| 4 | FLOAT | 4 | 浮点型,有效位数6-7,范围 [-3.4E38, 3.4E38] |
|
||||
| 5 | DOUBLE | 8 | 双精度浮点型,有效位数15-16,范围 [-1.7E308, 1.7E308] |
|
||||
| 6 | BINARY | 自定义 | 用于记录字符串,理论上,最长可以有65526字节,但由于每行数据最多64K字节,实际上限一般小于理论值。 binary仅支持字符串输入,字符串两端使用单引号引用,否则英文全部自动转化为小写。使用时须指定大小,如binary(20)定义了最长为20个字符的字符串,每个字符占1byte的存储空间。如果用户字符串超出20字节,将被自动截断。对于字符串内的单引号,可以用转义字符反斜线加单引号来表示, 即 **\’**。 |
|
||||
| 6 | BINARY | 自定义 | 用于记录字符串,理论上,最长可以有65526字节,但由于每行数据最多64K字节,实际上限一般小于理论值。 binary仅支持字符串输入,字符串两端使用单引号引用,否则英文全部自动转化为小写。使用时须指定大小,如binary(20)定义了最长为20个字符的字符串,每个字符占1byte的存储空间。如果用户字符串超出20字节将会报错。对于字符串内的单引号,可以用转义字符反斜线加单引号来表示, 即 **\’**。 |
|
||||
| 7 | SMALLINT | 2 | 短整型, 范围 [-32767, 32767], -32768用于NULL |
|
||||
| 8 | TINYINT | 1 | 单字节整型,范围 [-127, 127], -128用于NULL |
|
||||
| 9 | BOOL | 1 | 布尔型,{true, false} |
|
||||
| 10 | NCHAR | 自定义 | 用于记录非ASCII字符串,如中文字符。每个nchar字符占用4bytes的存储空间。字符串两端使用单引号引用,字符串内的单引号需用转义字符 **\’**。nchar使用时须指定字符串大小,类型为nchar(10)的列表示此列的字符串最多存储10个nchar字符,会固定占用40bytes的空间。如用户字符串长度超出声明长度,则将被自动截断。 |
|
||||
| 10 | NCHAR | 自定义 | 用于记录非ASCII字符串,如中文字符。每个nchar字符占用4bytes的存储空间。字符串两端使用单引号引用,字符串内的单引号需用转义字符 **\’**。nchar使用时须指定字符串大小,类型为nchar(10)的列表示此列的字符串最多存储10个nchar字符,会固定占用40bytes的空间。如用户字符串长度超出声明长度,则将会报错。 |
|
||||
|
||||
**Tips**: TDengine对SQL语句中的英文字符不区分大小写,自动转化为小写执行。因此用户大小写敏感的字符串及密码,需要使用单引号将字符串引起来。
|
||||
|
||||
|
|
|
@ -39,8 +39,8 @@ The full list of data types is listed below. For string types of data, we will
|
|||
| 6 | DOUBLE | 8 | A standard nullable double float type with 15-16 significant digits and a range of [-1.7E308, 1.7E308] |
|
||||
| 7 | BOOL | 1 | A nullable boolean type, [**`true`**, **`false`**] |
|
||||
| 8 | TIMESTAMP | 8 | A nullable timestamp type with the same usage as the primary column timestamp |
|
||||
| 9 | BINARY(*M*) | *M* | A nullable string type whose length is *M*, any exceeded chars will be automatically truncated, the maximum length of *M* is 65526, but as maximum row size is 64K bytes, the actual upper limit will generally less than 65526. This type of string only supports ASCii encoded chars. |
|
||||
| 10 | NCHAR(*M*) | 4 * *M* | A nullable string type whose length is *M*, any exceeded chars will be truncated. The **`NCHAR`** type supports Unicode encoded chars. |
|
||||
| 9 | BINARY(*M*) | *M* | A nullable string type whose length is *M*, error should be threw with exceeded chars, the maximum length of *M* is 65526, but as maximum row size is 64K bytes, the actual upper limit will generally less than 65526. This type of string only supports ASCii encoded chars. |
|
||||
| 10 | NCHAR(*M*) | 4 * *M* | A nullable string type whose length is *M*, error should be threw with exceeded chars. The **`NCHAR`** type supports Unicode encoded chars. |
|
||||
|
||||
All the keywords in a SQL statement are case-insensitive, but strings values are case-sensitive and must be quoted by a pair of `'` or `"`. To quote a `'` or a `"` , you can use the escape character `\`.
|
||||
|
||||
|
|
|
@ -1209,11 +1209,49 @@ TDengine在Window系统上提供的API与Linux系统是相同的, 应用程序
|
|||
其中,最常用的文件列出如下:
|
||||
|
||||
+ Client可执行文件: /usr/local/taos/bin/taos 软连接到 /usr/local/bin/taos
|
||||
|
||||
+ 配置文件: /usr/local/taos/cfg/taos.cfg 软连接到 /etc/taos/taos.cfg
|
||||
|
||||
+ 驱动程序目录: /usr/local/taos/driver/libtaos.1.6.5.1.dylib 软连接到 /usr/local/lib/libtaos.dylib
|
||||
|
||||
+ 驱动程序头文件: /usr/local/taos/include/taos.h 软连接到 /usr/local/include/taos.h
|
||||
|
||||
+ 日志目录(第一次运行程序时生成):~/TDengineLog
|
||||
|
||||
|
||||
|
||||
|
||||
## MQTT客户端
|
||||
|
||||
MQTT客户端实现了订阅MQTT Broker的特定Topic将Json数据进行转换入库的功能,任何终端只要将数据发给特定的Topic 即可,不用再编写转换器或者数据解析程序。如果终端量大,需要 Mqtt Broker 群集,这里不再详述。
|
||||
|
||||
#### 如何配置?
|
||||
|
||||
首先需要在 taos.cfg 中打开配置项 mqtt 用来启用, 再通过修改 mqttBrokerAddress 的值来配置连接,格式为:
|
||||
|
||||
> mqtt://username:password@hostname:port/path/
|
||||
|
||||
例如:
|
||||
|
||||
> mqtt://127.0.0.1:1883/taos/ mqtt://root@kissme@127.0.0.1:1883/taos/
|
||||
|
||||
|
||||
#### Topic 格式说明
|
||||
|
||||
Mqtt 的topic格式为
|
||||
|
||||
> /<path>/<token>/<db name>/<table name>/
|
||||
|
||||
因此TDengine的Mqtt客户端会订阅:
|
||||
|
||||
> /taos/+/+/+/+/
|
||||
|
||||
例如:
|
||||
|
||||
> /taos/token/db/t/
|
||||
|
||||
注意: 测试时如果需要使用到Mqtt Broker 推荐使用 [mosquitto](http://mosquitto.org/) ,客户端可以使用 [MQTT.fx ](http://www.jensd.de/)
|
||||
|
||||
|
||||
|
||||
[1]: https://search.maven.org/artifact/com.taosdata.jdbc/taos-jdbcdriver
|
||||
|
|
|
@ -166,6 +166,15 @@
|
|||
# start system monitor module
|
||||
# monitor 1
|
||||
|
||||
# start http service
|
||||
# mqtt 0
|
||||
|
||||
# mqtt uri
|
||||
# mqttBrokerAddress mqtt://username:password@hostname:1883/taos/
|
||||
|
||||
# mqtt client name
|
||||
# mqttBrokerClientId taos_mqtt
|
||||
|
||||
# maximum number of rows returned by the restful interface
|
||||
# restfulRowLimit 10240
|
||||
|
||||
|
@ -244,5 +253,8 @@
|
|||
# debug flag for system monitor
|
||||
# monitorDebugFlag 131
|
||||
|
||||
#debug flag for mqtt client
|
||||
# mqttDebugFlag 131
|
||||
|
||||
# debug flag for TAOS TIMER
|
||||
# tmrDebugFlag 131
|
||||
|
|
|
@ -175,7 +175,7 @@ SSqlExpr* tscSqlExprAppend(SQueryInfo* pQueryInfo, int16_t functionId, SColumnIn
|
|||
|
||||
SSqlExpr* tscSqlExprUpdate(SQueryInfo* pQueryInfo, int32_t index, int16_t functionId, int16_t srcColumnIndex, int16_t type,
|
||||
int16_t size);
|
||||
int32_t tscSqlExprNumOfExprs(SQueryInfo* pQueryInfo);
|
||||
size_t tscSqlExprNumOfExprs(SQueryInfo* pQueryInfo);
|
||||
|
||||
SSqlExpr* tscSqlExprGet(SQueryInfo* pQueryInfo, int32_t index);
|
||||
void tscSqlExprCopy(SArray* dst, const SArray* src, uint64_t uid, bool deepcopy);
|
||||
|
|
|
@ -84,7 +84,7 @@ typedef struct SSqlExpr {
|
|||
int16_t functionId; // function id in aAgg array
|
||||
int16_t resType; // return value type
|
||||
int16_t resBytes; // length of return value
|
||||
int16_t interBytes; // inter result buffer size
|
||||
int32_t interBytes; // inter result buffer size
|
||||
int16_t numOfParams; // argument value of each function
|
||||
tVariant param[3]; // parameters are not more than 3
|
||||
int32_t offset; // sub result column value of arithmetic expression.
|
||||
|
@ -320,7 +320,7 @@ typedef struct SSqlObj {
|
|||
tsem_t rspSem;
|
||||
SSqlCmd cmd;
|
||||
SSqlRes res;
|
||||
uint8_t numOfSubs;
|
||||
uint16_t numOfSubs;
|
||||
struct SSqlObj **pSubs;
|
||||
struct SSqlObj * prev, *next;
|
||||
} SSqlObj;
|
||||
|
|
|
@ -57,6 +57,7 @@ void doAsyncQuery(STscObj* pObj, SSqlObj* pSql, void (*fp)(), void* param, const
|
|||
}
|
||||
|
||||
pSql->sqlstr = realloc(pSql->sqlstr, sqlLen + 1);
|
||||
|
||||
if (pSql->sqlstr == NULL) {
|
||||
tscError("%p failed to malloc sql string buffer", pSql);
|
||||
tscQueueAsyncError(fp, param, TSDB_CODE_CLI_OUT_OF_MEMORY);
|
||||
|
@ -165,7 +166,7 @@ static void tscProcessAsyncRetrieveImpl(void *param, TAOS_RES *tres, int numOfRo
|
|||
SSqlRes *pRes = &pSql->res;
|
||||
|
||||
if ((pRes->qhandle == 0 || numOfRows != 0) && pCmd->command < TSDB_SQL_LOCAL) {
|
||||
if (pRes->qhandle == 0) {
|
||||
if (pRes->qhandle == 0 && numOfRows != 0) {
|
||||
tscError("qhandle is NULL");
|
||||
} else {
|
||||
pRes->code = numOfRows;
|
||||
|
|
|
@ -153,7 +153,7 @@ typedef struct SRateInfo {
|
|||
|
||||
|
||||
int32_t getResultDataInfo(int32_t dataType, int32_t dataBytes, int32_t functionId, int32_t param, int16_t *type,
|
||||
int16_t *bytes, int16_t *interBytes, int16_t extLength, bool isSuperTable) {
|
||||
int16_t *bytes, int32_t *interBytes, int16_t extLength, bool isSuperTable) {
|
||||
if (!isValidDataType(dataType, dataBytes)) {
|
||||
tscError("Illegal data type %d or data type length %d", dataType, dataBytes);
|
||||
return TSDB_CODE_INVALID_SQL;
|
||||
|
@ -478,7 +478,7 @@ int32_t count_load_data_info(SQLFunctionCtx *pCtx, TSKEY start, TSKEY end, int32
|
|||
if (colId == PRIMARYKEY_TIMESTAMP_COL_INDEX) {
|
||||
return BLK_DATA_NO_NEEDED;
|
||||
} else {
|
||||
return BLK_DATA_FILEDS_NEEDED;
|
||||
return BLK_DATA_STATIS_NEEDED;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -690,7 +690,7 @@ static void sum_func_second_merge(SQLFunctionCtx *pCtx) {
|
|||
}
|
||||
|
||||
static int32_t precal_req_load_info(SQLFunctionCtx *pCtx, TSKEY start, TSKEY end, int32_t colId) {
|
||||
return BLK_DATA_FILEDS_NEEDED;
|
||||
return BLK_DATA_STATIS_NEEDED;
|
||||
}
|
||||
|
||||
static int32_t data_req_load_info(SQLFunctionCtx *pCtx, TSKEY start, TSKEY end, int32_t colId) {
|
||||
|
@ -1848,13 +1848,14 @@ static void last_row_function(SQLFunctionCtx *pCtx) {
|
|||
pResInfo->hasResult = DATA_SET_FLAG;
|
||||
|
||||
SLastrowInfo *pInfo = (SLastrowInfo *)pResInfo->interResultBuf;
|
||||
pInfo->ts = pCtx->param[0].i64Key;
|
||||
pInfo->ts = pCtx->ptsList[0];
|
||||
|
||||
pInfo->hasResult = DATA_SET_FLAG;
|
||||
|
||||
// set the result to final result buffer
|
||||
if (pResInfo->superTableQ) {
|
||||
SLastrowInfo *pInfo1 = (SLastrowInfo *)(pCtx->aOutputBuf + pCtx->inputBytes);
|
||||
pInfo1->ts = pCtx->param[0].i64Key;
|
||||
pInfo1->ts = pCtx->ptsList[0];
|
||||
pInfo1->hasResult = DATA_SET_FLAG;
|
||||
|
||||
DO_UPDATE_TAG_COLUMNS(pCtx, pInfo1->ts);
|
||||
|
@ -1904,12 +1905,12 @@ static void valuePairAssign(tValuePair *dst, int16_t type, const char *val, int6
|
|||
memcpy(dst->pTags, pTags, (size_t)pTagInfo->tagsLen);
|
||||
} else { // the tags are dumped from the ctx tag fields
|
||||
for (int32_t i = 0; i < pTagInfo->numOfTagCols; ++i) {
|
||||
SQLFunctionCtx* __ctx = pTagInfo->pTagCtxList[i];
|
||||
if (__ctx->functionId == TSDB_FUNC_TS_DUMMY) {
|
||||
__ctx->tag = (tVariant) {.nType = TSDB_DATA_TYPE_BIGINT, .i64Key = tsKey};
|
||||
SQLFunctionCtx* ctx = pTagInfo->pTagCtxList[i];
|
||||
if (ctx->functionId == TSDB_FUNC_TS_DUMMY) {
|
||||
ctx->tag = (tVariant) {.nType = TSDB_DATA_TYPE_BIGINT, .i64Key = tsKey};
|
||||
}
|
||||
|
||||
tVariantDump(&pTagInfo->pTagCtxList[i]->tag, dst->pTags + size, pTagInfo->pTagCtxList[i]->tag.nType);
|
||||
tVariantDump(&ctx->tag, dst->pTags + size, ctx->tag.nType, true);
|
||||
size += pTagInfo->pTagCtxList[i]->outputBytes;
|
||||
}
|
||||
}
|
||||
|
@ -2226,7 +2227,6 @@ static STopBotInfo *getTopBotOutputInfo(SQLFunctionCtx *pCtx) {
|
|||
static void buildTopBotStruct(STopBotInfo *pTopBotInfo, SQLFunctionCtx *pCtx) {
|
||||
char *tmp = (char *)pTopBotInfo + sizeof(STopBotInfo);
|
||||
pTopBotInfo->res = (tValuePair**) tmp;
|
||||
|
||||
tmp += POINTER_BYTES * pCtx->param[0].i64Key;
|
||||
|
||||
size_t size = sizeof(tValuePair) + pCtx->tagInfo.tagsLen;
|
||||
|
@ -2981,14 +2981,7 @@ static void tag_project_function(SQLFunctionCtx *pCtx) {
|
|||
assert(pCtx->inputBytes == pCtx->outputBytes);
|
||||
|
||||
for (int32_t i = 0; i < pCtx->size; ++i) {
|
||||
char* output = pCtx->aOutputBuf;
|
||||
|
||||
if (pCtx->tag.nType == TSDB_DATA_TYPE_BINARY || pCtx->tag.nType == TSDB_DATA_TYPE_NCHAR) {
|
||||
varDataSetLen(output, pCtx->tag.nLen);
|
||||
tVariantDump(&pCtx->tag, varDataVal(output), pCtx->outputType);
|
||||
} else {
|
||||
tVariantDump(&pCtx->tag, output, pCtx->outputType);
|
||||
}
|
||||
tVariantDump(&pCtx->tag, pCtx->aOutputBuf, pCtx->outputType, true);
|
||||
|
||||
pCtx->aOutputBuf += pCtx->outputBytes;
|
||||
}
|
||||
|
@ -2997,13 +2990,7 @@ static void tag_project_function(SQLFunctionCtx *pCtx) {
|
|||
static void tag_project_function_f(SQLFunctionCtx *pCtx, int32_t index) {
|
||||
INC_INIT_VAL(pCtx, 1);
|
||||
|
||||
char* output = pCtx->aOutputBuf;
|
||||
if (pCtx->tag.nType == TSDB_DATA_TYPE_BINARY || pCtx->tag.nType == TSDB_DATA_TYPE_NCHAR) {
|
||||
*(int16_t*) output = pCtx->tag.nLen;
|
||||
output += VARSTR_HEADER_SIZE;
|
||||
}
|
||||
|
||||
tVariantDump(&pCtx->tag, output, pCtx->tag.nType);
|
||||
tVariantDump(&pCtx->tag, pCtx->aOutputBuf, pCtx->tag.nType, true);
|
||||
pCtx->aOutputBuf += pCtx->outputBytes;
|
||||
}
|
||||
|
||||
|
@ -3016,30 +3003,12 @@ static void tag_project_function_f(SQLFunctionCtx *pCtx, int32_t index) {
|
|||
*/
|
||||
static void tag_function(SQLFunctionCtx *pCtx) {
|
||||
SET_VAL(pCtx, 1, 1);
|
||||
|
||||
char* output = pCtx->aOutputBuf;
|
||||
|
||||
// todo refactor to dump length presented string(var string)
|
||||
if (pCtx->tag.nType == TSDB_DATA_TYPE_BINARY || pCtx->tag.nType == TSDB_DATA_TYPE_NCHAR) {
|
||||
*(int16_t*) output = pCtx->tag.nLen;
|
||||
output += VARSTR_HEADER_SIZE;
|
||||
}
|
||||
|
||||
tVariantDump(&pCtx->tag, output, pCtx->tag.nType);
|
||||
tVariantDump(&pCtx->tag, pCtx->aOutputBuf, pCtx->tag.nType, true);
|
||||
}
|
||||
|
||||
static void tag_function_f(SQLFunctionCtx *pCtx, int32_t index) {
|
||||
SET_VAL(pCtx, 1, 1);
|
||||
|
||||
char* output = pCtx->aOutputBuf;
|
||||
|
||||
// todo refactor to dump length presented string(var string)
|
||||
if (pCtx->tag.nType == TSDB_DATA_TYPE_BINARY || pCtx->tag.nType == TSDB_DATA_TYPE_NCHAR) {
|
||||
*(int16_t*) output = pCtx->tag.nLen;
|
||||
output += VARSTR_HEADER_SIZE;
|
||||
}
|
||||
|
||||
tVariantDump(&pCtx->tag, output, pCtx->tag.nType);
|
||||
tVariantDump(&pCtx->tag, pCtx->aOutputBuf, pCtx->tag.nType, true);
|
||||
}
|
||||
|
||||
static void copy_function(SQLFunctionCtx *pCtx) {
|
||||
|
@ -3853,15 +3822,15 @@ void twa_function_finalizer(SQLFunctionCtx *pCtx) {
|
|||
}
|
||||
|
||||
/**
|
||||
* param[1]: default value/previous value of specified timestamp
|
||||
* param[2]: next value of specified timestamp
|
||||
* param[3]: denotes if the result is a precious result or interpolation results
|
||||
*
|
||||
* @param pCtx
|
||||
*/
|
||||
static void interp_function(SQLFunctionCtx *pCtx) {
|
||||
// at this point, the value is existed, return directly
|
||||
if (pCtx->param[3].i64Key == 1) {
|
||||
SResultInfo *pResInfo = GET_RES_INFO(pCtx);
|
||||
SInterpInfoDetail* pInfo = pResInfo->interResultBuf;
|
||||
|
||||
if (pCtx->size == 1) {
|
||||
char *pData = GET_INPUT_CHAR(pCtx);
|
||||
assignVal(pCtx->aOutputBuf, pData, pCtx->inputBytes, pCtx->inputType);
|
||||
} else {
|
||||
|
@ -3869,76 +3838,65 @@ static void interp_function(SQLFunctionCtx *pCtx) {
|
|||
* use interpolation to generate the result.
|
||||
* Note: the result of primary timestamp column uses the timestamp specified by user in the query sql
|
||||
*/
|
||||
assert(pCtx->param[3].i64Key == 2);
|
||||
assert(pCtx->size == 2);
|
||||
if (pInfo->type == TSDB_FILL_NONE) { // set no output result
|
||||
return;
|
||||
}
|
||||
|
||||
SInterpInfo interpInfo = *(SInterpInfo *)pCtx->aOutputBuf;
|
||||
SInterpInfoDetail *pInfoDetail = interpInfo.pInterpDetail;
|
||||
|
||||
/* set no output result */
|
||||
if (pInfoDetail->type == TSDB_FILL_NONE) {
|
||||
pCtx->param[3].i64Key = 0;
|
||||
} else if (pInfoDetail->primaryCol == 1) {
|
||||
*(TSKEY *)pCtx->aOutputBuf = pInfoDetail->ts;
|
||||
if (pInfo->primaryCol == 1) {
|
||||
*(TSKEY *) pCtx->aOutputBuf = pInfo->ts;
|
||||
} else {
|
||||
if (pInfoDetail->type == TSDB_FILL_NULL) {
|
||||
if (pInfo->type == TSDB_FILL_NULL) {
|
||||
if (pCtx->outputType == TSDB_DATA_TYPE_BINARY || pCtx->outputType == TSDB_DATA_TYPE_NCHAR) {
|
||||
setVardataNull(pCtx->aOutputBuf, pCtx->outputType);
|
||||
} else {
|
||||
setNull(pCtx->aOutputBuf, pCtx->outputType, pCtx->outputBytes);
|
||||
}
|
||||
} else if (pInfoDetail->type == TSDB_FILL_SET_VALUE) {
|
||||
tVariantDump(&pCtx->param[1], pCtx->aOutputBuf, pCtx->inputType);
|
||||
} else if (pInfoDetail->type == TSDB_FILL_PREV) {
|
||||
char *data = pCtx->param[1].pz;
|
||||
char *pVal = data + TSDB_KEYSIZE;
|
||||
|
||||
if (pCtx->outputType == TSDB_DATA_TYPE_FLOAT) {
|
||||
float v = GET_DOUBLE_VAL(pVal);
|
||||
assignVal(pCtx->aOutputBuf, (const char*) &v, pCtx->outputBytes, pCtx->outputType);
|
||||
} else {
|
||||
assignVal(pCtx->aOutputBuf, pVal, pCtx->outputBytes, pCtx->outputType);
|
||||
}
|
||||
|
||||
} else if (pInfoDetail->type == TSDB_FILL_LINEAR) {
|
||||
char *data1 = pCtx->param[1].pz;
|
||||
char *data2 = pCtx->param[2].pz;
|
||||
|
||||
char *pVal1 = data1 + TSDB_KEYSIZE;
|
||||
char *pVal2 = data2 + TSDB_KEYSIZE;
|
||||
|
||||
SPoint point1 = {.key = *(TSKEY *)data1, .val = &pCtx->param[1].i64Key};
|
||||
SPoint point2 = {.key = *(TSKEY *)data2, .val = &pCtx->param[2].i64Key};
|
||||
|
||||
SPoint point = {.key = pInfoDetail->ts, .val = pCtx->aOutputBuf};
|
||||
|
||||
|
||||
SET_VAL(pCtx, pCtx->size, 1);
|
||||
} else if (pInfo->type == TSDB_FILL_SET_VALUE) {
|
||||
tVariantDump(&pCtx->param[1], pCtx->aOutputBuf, pCtx->inputType, true);
|
||||
} else if (pInfo->type == TSDB_FILL_PREV) {
|
||||
char *data = GET_INPUT_CHAR_INDEX(pCtx, 0);
|
||||
assignVal(pCtx->aOutputBuf, data, pCtx->outputBytes, pCtx->outputType);
|
||||
|
||||
SET_VAL(pCtx, pCtx->size, 1);
|
||||
} else if (pInfo->type == TSDB_FILL_LINEAR) {
|
||||
char *data1 = GET_INPUT_CHAR_INDEX(pCtx, 0);
|
||||
char *data2 = GET_INPUT_CHAR_INDEX(pCtx, 1);
|
||||
|
||||
TSKEY key1 = pCtx->ptsList[0];
|
||||
TSKEY key2 = pCtx->ptsList[1];
|
||||
|
||||
SPoint point1 = {.key = key1, .val = data1};
|
||||
SPoint point2 = {.key = key2, .val = data2};
|
||||
|
||||
SPoint point = {.key = pInfo->ts, .val = pCtx->aOutputBuf};
|
||||
|
||||
int32_t srcType = pCtx->inputType;
|
||||
if ((srcType >= TSDB_DATA_TYPE_TINYINT && srcType <= TSDB_DATA_TYPE_BIGINT) ||
|
||||
srcType == TSDB_DATA_TYPE_TIMESTAMP || srcType == TSDB_DATA_TYPE_DOUBLE) {
|
||||
point1.val = pVal1;
|
||||
|
||||
point2.val = pVal2;
|
||||
|
||||
if (isNull(pVal1, srcType) || isNull(pVal2, srcType)) {
|
||||
point1.val = data1;
|
||||
point2.val = data2;
|
||||
|
||||
if (isNull(data1, srcType) || isNull(data2, srcType)) {
|
||||
setNull(pCtx->aOutputBuf, srcType, pCtx->inputBytes);
|
||||
} else {
|
||||
taosDoLinearInterpolation(pCtx->outputType, &point1, &point2, &point);
|
||||
}
|
||||
} else if (srcType == TSDB_DATA_TYPE_FLOAT) {
|
||||
float v1 = GET_DOUBLE_VAL(pVal1);
|
||||
float v2 = GET_DOUBLE_VAL(pVal2);
|
||||
|
||||
point1.val = &v1;
|
||||
point2.val = &v2;
|
||||
|
||||
if (isNull(pVal1, srcType) || isNull(pVal2, srcType)) {
|
||||
point1.val = data1;
|
||||
point2.val = data2;
|
||||
|
||||
if (isNull(data1, srcType) || isNull(data2, srcType)) {
|
||||
setNull(pCtx->aOutputBuf, srcType, pCtx->inputBytes);
|
||||
} else {
|
||||
taosDoLinearInterpolation(pCtx->outputType, &point1, &point2, &point);
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
if (srcType == TSDB_DATA_TYPE_BINARY || srcType == TSDB_DATA_TYPE_NCHAR) {
|
||||
setVardataNull(pCtx->aOutputBuf, pCtx->inputBytes);
|
||||
setVardataNull(pCtx->aOutputBuf, pCtx->inputType);
|
||||
} else {
|
||||
setNull(pCtx->aOutputBuf, srcType, pCtx->inputBytes);
|
||||
}
|
||||
|
@ -3946,15 +3904,8 @@ static void interp_function(SQLFunctionCtx *pCtx) {
|
|||
}
|
||||
}
|
||||
|
||||
free(interpInfo.pInterpDetail);
|
||||
}
|
||||
|
||||
pCtx->size = pCtx->param[3].i64Key;
|
||||
|
||||
tVariantDestroy(&pCtx->param[1]);
|
||||
tVariantDestroy(&pCtx->param[2]);
|
||||
|
||||
// data in the check operation are all null, not output
|
||||
SET_VAL(pCtx, pCtx->size, 1);
|
||||
}
|
||||
|
||||
|
@ -4910,7 +4861,7 @@ SQLAggFuncElem aAggs[] = {{
|
|||
"interp",
|
||||
TSDB_FUNC_INTERP,
|
||||
TSDB_FUNC_INTERP,
|
||||
TSDB_FUNCSTATE_SO | TSDB_FUNCSTATE_OF | TSDB_FUNCSTATE_STABLE | TSDB_FUNCSTATE_NEED_TS,
|
||||
TSDB_FUNCSTATE_SO | TSDB_FUNCSTATE_OF | TSDB_FUNCSTATE_STABLE | TSDB_FUNCSTATE_NEED_TS ,
|
||||
function_setup,
|
||||
interp_function,
|
||||
do_sum_f, // todo filter handle
|
||||
|
@ -4918,7 +4869,7 @@ SQLAggFuncElem aAggs[] = {{
|
|||
doFinalizer,
|
||||
noop1,
|
||||
copy_function,
|
||||
no_data_info,
|
||||
data_req_load_info,
|
||||
},
|
||||
{
|
||||
// 28
|
||||
|
|
|
@ -142,7 +142,7 @@ static int setColumnFilterInfoForTimestamp(SQueryInfo* pQueryInfo, tVariant* pVa
|
|||
return invalidSqlErrMsg(pQueryInfo->msg, msg);
|
||||
}
|
||||
} else {
|
||||
if (tVariantDump(pVar, (char*)&time, TSDB_DATA_TYPE_BIGINT)) {
|
||||
if (tVariantDump(pVar, (char*)&time, TSDB_DATA_TYPE_BIGINT, true)) {
|
||||
return invalidSqlErrMsg(pQueryInfo->msg, msg);
|
||||
}
|
||||
}
|
||||
|
@ -1403,7 +1403,6 @@ int32_t addProjectionExprAndResultField(SQueryInfo* pQueryInfo, tSQLExprItem* pI
|
|||
SSchema colSchema = {.type = TSDB_DATA_TYPE_BINARY, .bytes = TSDB_TABLE_NAME_LEN + VARSTR_HEADER_SIZE};
|
||||
strcpy(colSchema.name, TSQL_TBNAME_L);
|
||||
|
||||
pQueryInfo->type = TSDB_QUERY_TYPE_STABLE_QUERY;
|
||||
tscAddSpecialColumnForSelect(pQueryInfo, startPos, TSDB_FUNC_TAGPRJ, &index, &colSchema, true);
|
||||
} else {
|
||||
STableMetaInfo* pTableMetaInfo = tscGetMetaInfo(pQueryInfo, index.tableIndex);
|
||||
|
@ -1595,7 +1594,7 @@ int32_t addExprAndResultField(SQueryInfo* pQueryInfo, int32_t colIndex, tSQLExpr
|
|||
|
||||
int16_t resultType = 0;
|
||||
int16_t resultSize = 0;
|
||||
int16_t intermediateResSize = 0;
|
||||
int32_t intermediateResSize = 0;
|
||||
|
||||
int16_t functionID = 0;
|
||||
if (changeFunctionID(optr, &functionID) != TSDB_CODE_SUCCESS) {
|
||||
|
@ -1628,14 +1627,14 @@ int32_t addExprAndResultField(SQueryInfo* pQueryInfo, int32_t colIndex, tSQLExpr
|
|||
if (optr == TK_LEASTSQUARES) {
|
||||
/* set the leastsquares parameters */
|
||||
char val[8] = {0};
|
||||
if (tVariantDump(&pParamElem[1].pNode->val, val, TSDB_DATA_TYPE_DOUBLE) < 0) {
|
||||
if (tVariantDump(&pParamElem[1].pNode->val, val, TSDB_DATA_TYPE_DOUBLE, true) < 0) {
|
||||
return TSDB_CODE_INVALID_SQL;
|
||||
}
|
||||
|
||||
addExprParams(pExpr, val, TSDB_DATA_TYPE_DOUBLE, DOUBLE_BYTES, 0);
|
||||
|
||||
memset(val, 0, tListLen(val));
|
||||
if (tVariantDump(&pParamElem[2].pNode->val, val, TSDB_DATA_TYPE_DOUBLE) < 0) {
|
||||
if (tVariantDump(&pParamElem[2].pNode->val, val, TSDB_DATA_TYPE_DOUBLE, true) < 0) {
|
||||
return TSDB_CODE_INVALID_SQL;
|
||||
}
|
||||
|
||||
|
@ -1795,7 +1794,7 @@ int32_t addExprAndResultField(SQueryInfo* pQueryInfo, int32_t colIndex, tSQLExpr
|
|||
SSqlExpr* pExpr = NULL;
|
||||
|
||||
if (optr == TK_PERCENTILE || optr == TK_APERCENTILE) {
|
||||
tVariantDump(pVariant, val, TSDB_DATA_TYPE_DOUBLE);
|
||||
tVariantDump(pVariant, val, TSDB_DATA_TYPE_DOUBLE, true);
|
||||
|
||||
double dp = GET_DOUBLE_VAL(val);
|
||||
if (dp < 0 || dp > TOP_BOTTOM_QUERY_LIMIT) {
|
||||
|
@ -1818,7 +1817,7 @@ int32_t addExprAndResultField(SQueryInfo* pQueryInfo, int32_t colIndex, tSQLExpr
|
|||
pExpr = tscSqlExprAppend(pQueryInfo, functionId, &index, resultType, resultSize, resultSize, false);
|
||||
addExprParams(pExpr, val, TSDB_DATA_TYPE_DOUBLE, sizeof(double), 0);
|
||||
} else {
|
||||
tVariantDump(pVariant, val, TSDB_DATA_TYPE_BIGINT);
|
||||
tVariantDump(pVariant, val, TSDB_DATA_TYPE_BIGINT, true);
|
||||
|
||||
int64_t nTop = *((int32_t*)val);
|
||||
if (nTop <= 0 || nTop > 100) { // todo use macro
|
||||
|
@ -1902,7 +1901,7 @@ int32_t addExprAndResultField(SQueryInfo* pQueryInfo, int32_t colIndex, tSQLExpr
|
|||
|
||||
int16_t bytes = 0;
|
||||
int16_t type = 0;
|
||||
int16_t inter = 0;
|
||||
int32_t inter = 0;
|
||||
|
||||
int32_t ret = getResultDataInfo(s.type, s.bytes, TSDB_FUNC_TID_TAG, 0, &type, &bytes, &inter, 0, 0);
|
||||
assert(ret == TSDB_CODE_SUCCESS);
|
||||
|
@ -2288,7 +2287,7 @@ int32_t tscTansformSQLFuncForSTableQuery(SQueryInfo* pQueryInfo) {
|
|||
|
||||
int16_t bytes = 0;
|
||||
int16_t type = 0;
|
||||
int16_t intermediateBytes = 0;
|
||||
int32_t interBytes = 0;
|
||||
|
||||
size_t size = tscSqlExprNumOfExprs(pQueryInfo);
|
||||
for (int32_t k = 0; k < size; ++k) {
|
||||
|
@ -2302,13 +2301,13 @@ int32_t tscTansformSQLFuncForSTableQuery(SQueryInfo* pQueryInfo) {
|
|||
(functionId >= TSDB_FUNC_FIRST_DST && functionId <= TSDB_FUNC_LAST_DST) ||
|
||||
(functionId >= TSDB_FUNC_RATE && functionId <= TSDB_FUNC_AVG_IRATE)) {
|
||||
if (getResultDataInfo(pSrcSchema->type, pSrcSchema->bytes, functionId, pExpr->param[0].i64Key, &type, &bytes,
|
||||
&intermediateBytes, 0, true) != TSDB_CODE_SUCCESS) {
|
||||
&interBytes, 0, true) != TSDB_CODE_SUCCESS) {
|
||||
return TSDB_CODE_INVALID_SQL;
|
||||
}
|
||||
|
||||
tscSqlExprUpdate(pQueryInfo, k, functionId, pExpr->colInfo.colIndex, TSDB_DATA_TYPE_BINARY, bytes);
|
||||
// todo refactor
|
||||
pExpr->interBytes = intermediateBytes;
|
||||
pExpr->interBytes = interBytes;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2328,27 +2327,23 @@ void tscRestoreSQLFuncForSTableQuery(SQueryInfo* pQueryInfo) {
|
|||
SSqlExpr* pExpr = tscSqlExprGet(pQueryInfo, i);
|
||||
SSchema* pSchema = tscGetTableColumnSchema(pTableMetaInfo->pTableMeta, pExpr->colInfo.colIndex);
|
||||
|
||||
// if (/*(pExpr->functionId >= TSDB_FUNC_FIRST_DST && pExpr->functionId <= TSDB_FUNC_LAST_DST) ||
|
||||
// (pExpr->functionId >= TSDB_FUNC_SUM && pExpr->functionId <= TSDB_FUNC_MAX) ||
|
||||
// pExpr->functionId == TSDB_FUNC_LAST_ROW*/) {
|
||||
// the final result size and type in the same as query on single table.
|
||||
// so here, set the flag to be false;
|
||||
int16_t inter = 0;
|
||||
|
||||
int32_t functionId = pExpr->functionId;
|
||||
if (functionId >= TSDB_FUNC_TS && functionId <= TSDB_FUNC_DIFF) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (functionId == TSDB_FUNC_FIRST_DST) {
|
||||
functionId = TSDB_FUNC_FIRST;
|
||||
} else if (functionId == TSDB_FUNC_LAST_DST) {
|
||||
functionId = TSDB_FUNC_LAST;
|
||||
}
|
||||
|
||||
getResultDataInfo(pSchema->type, pSchema->bytes, functionId, 0, &pExpr->resType, &pExpr->resBytes,
|
||||
&inter, 0, false);
|
||||
// }
|
||||
// the final result size and type in the same as query on single table.
|
||||
// so here, set the flag to be false;
|
||||
int32_t inter = 0;
|
||||
|
||||
int32_t functionId = pExpr->functionId;
|
||||
if (functionId >= TSDB_FUNC_TS && functionId <= TSDB_FUNC_DIFF) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (functionId == TSDB_FUNC_FIRST_DST) {
|
||||
functionId = TSDB_FUNC_FIRST;
|
||||
} else if (functionId == TSDB_FUNC_LAST_DST) {
|
||||
functionId = TSDB_FUNC_LAST;
|
||||
}
|
||||
|
||||
getResultDataInfo(pSchema->type, pSchema->bytes, functionId, 0, &pExpr->resType, &pExpr->resBytes,
|
||||
&inter, 0, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2631,23 +2626,23 @@ static int32_t doExtractColumnFilterInfo(SQueryInfo* pQueryInfo, SColumnFilterIn
|
|||
}
|
||||
|
||||
if (pExpr->nSQLOptr == TK_LE || pExpr->nSQLOptr == TK_LT) {
|
||||
tVariantDump(&pRight->val, (char*)&pColumnFilter->upperBndd, colType);
|
||||
tVariantDump(&pRight->val, (char*)&pColumnFilter->upperBndd, colType, false);
|
||||
} else { // TK_GT,TK_GE,TK_EQ,TK_NE are based on the pColumn->lowerBndd
|
||||
if (colType == TSDB_DATA_TYPE_BINARY) {
|
||||
pColumnFilter->pz = (int64_t)calloc(1, pRight->val.nLen + 1);
|
||||
pColumnFilter->len = pRight->val.nLen;
|
||||
|
||||
tVariantDump(&pRight->val, (char*)pColumnFilter->pz, colType);
|
||||
tVariantDump(&pRight->val, (char*)pColumnFilter->pz, colType, false);
|
||||
} else if (colType == TSDB_DATA_TYPE_NCHAR) {
|
||||
// pRight->val.nLen + 1 is larger than the actual nchar string length
|
||||
pColumnFilter->pz = (int64_t)calloc(1, (pRight->val.nLen + 1) * TSDB_NCHAR_SIZE);
|
||||
|
||||
tVariantDump(&pRight->val, (char*)pColumnFilter->pz, colType);
|
||||
tVariantDump(&pRight->val, (char*)pColumnFilter->pz, colType, false);
|
||||
|
||||
size_t len = wcslen((wchar_t*)pColumnFilter->pz);
|
||||
pColumnFilter->len = len * TSDB_NCHAR_SIZE;
|
||||
} else {
|
||||
tVariantDump(&pRight->val, (char*)&pColumnFilter->lowerBndd, colType);
|
||||
tVariantDump(&pRight->val, (char*)&pColumnFilter->lowerBndd, colType, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3336,9 +3331,8 @@ static int32_t handleExprInQueryCond(SQueryInfo* pQueryInfo, tSQLExpr** pExpr, S
|
|||
|
||||
*pExpr = NULL; // remove this expression
|
||||
*type = TSQL_EXPR_TS;
|
||||
} else if (index.columnIndex >= tscGetNumOfColumns(pTableMeta) ||
|
||||
index.columnIndex == TSDB_TBNAME_COLUMN_INDEX) { // query on tags
|
||||
// check for tag query condition
|
||||
} else if (index.columnIndex >= tscGetNumOfColumns(pTableMeta) || index.columnIndex == TSDB_TBNAME_COLUMN_INDEX) {
|
||||
// query on tags, check for tag query condition
|
||||
if (UTIL_TABLE_IS_NORMAL_TABLE(pTableMetaInfo)) {
|
||||
return invalidSqlErrMsg(pQueryInfo->msg, msg1);
|
||||
}
|
||||
|
@ -3933,7 +3927,7 @@ int32_t getTimeRange(STimeWindow* win, tSQLExpr* pRight, int32_t optr, int16_t t
|
|||
* failed to parse timestamp in regular formation, try next
|
||||
* it may be a epoch time in string format
|
||||
*/
|
||||
tVariantDump(&pRight->val, (char*)&val, TSDB_DATA_TYPE_BIGINT);
|
||||
tVariantDump(&pRight->val, (char*)&val, TSDB_DATA_TYPE_BIGINT, true);
|
||||
|
||||
/*
|
||||
* transfer it into MICROSECOND format if it is a string, since for
|
||||
|
@ -4070,14 +4064,13 @@ int32_t parseFillClause(SQueryInfo* pQueryInfo, SQuerySQL* pQuerySQL) {
|
|||
continue;
|
||||
}
|
||||
|
||||
int32_t ret = tVariantDump(&pFillToken->a[j].pVar, (char*)&pQueryInfo->fillVal[i], pFields->type);
|
||||
int32_t ret = tVariantDump(&pFillToken->a[j].pVar, (char*)&pQueryInfo->fillVal[i], pFields->type, true);
|
||||
if (ret != TSDB_CODE_SUCCESS) {
|
||||
return invalidSqlErrMsg(pQueryInfo->msg, msg);
|
||||
}
|
||||
}
|
||||
|
||||
if ((pFillToken->nExpr < size) ||
|
||||
((pFillToken->nExpr - 1 < size) && (tscIsPointInterpQuery(pQueryInfo)))) {
|
||||
if ((pFillToken->nExpr < size) || ((pFillToken->nExpr - 1 < size) && (tscIsPointInterpQuery(pQueryInfo)))) {
|
||||
tVariantListItem* lastItem = &pFillToken->a[pFillToken->nExpr - 1];
|
||||
|
||||
for (int32_t i = numOfFillVal; i < size; ++i) {
|
||||
|
@ -4086,7 +4079,7 @@ int32_t parseFillClause(SQueryInfo* pQueryInfo, SQuerySQL* pQuerySQL) {
|
|||
if (pFields->type == TSDB_DATA_TYPE_BINARY || pFields->type == TSDB_DATA_TYPE_NCHAR) {
|
||||
setVardataNull((char*) &pQueryInfo->fillVal[i], pFields->type);
|
||||
} else {
|
||||
tVariantDump(&lastItem->pVar, (char*)&pQueryInfo->fillVal[i], pFields->type);
|
||||
tVariantDump(&lastItem->pVar, (char*)&pQueryInfo->fillVal[i], pFields->type, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4168,6 +4161,10 @@ int32_t parseOrderbyClause(SQueryInfo* pQueryInfo, SQuerySQL* pQuerySql, SSchema
|
|||
if (index.columnIndex >= tscGetNumOfColumns(pTableMetaInfo->pTableMeta)) {
|
||||
int32_t relTagIndex = index.columnIndex - tscGetNumOfColumns(pTableMetaInfo->pTableMeta);
|
||||
|
||||
// it is a tag column
|
||||
if (pQueryInfo->groupbyExpr.columnInfo == NULL) {
|
||||
return invalidSqlErrMsg(pQueryInfo->msg, msg2);
|
||||
}
|
||||
SColIndex* pColIndex = taosArrayGet(pQueryInfo->groupbyExpr.columnInfo, 0);
|
||||
if (relTagIndex == pColIndex->colIndex) {
|
||||
orderByTags = true;
|
||||
|
@ -4420,10 +4417,10 @@ int32_t setAlterTableInfo(SSqlObj* pSql, struct SSqlInfo* pInfo) {
|
|||
}
|
||||
|
||||
SSchema* pTagsSchema = tscGetTableColumnSchema(pTableMetaInfo->pTableMeta, columnIndex.columnIndex);
|
||||
if (tVariantDump(&pVarList->a[1].pVar, pAlterSQL->tagData.data /*pCmd->payload*/, pTagsSchema->type) !=
|
||||
TSDB_CODE_SUCCESS) {
|
||||
if (tVariantDump(&pVarList->a[1].pVar, pAlterSQL->tagData.data, pTagsSchema->type, true) != TSDB_CODE_SUCCESS) {
|
||||
return invalidSqlErrMsg(pQueryInfo->msg, msg13);
|
||||
}
|
||||
|
||||
pAlterSQL->tagData.dataLen = pTagsSchema->bytes;
|
||||
|
||||
// validate the length of binary
|
||||
|
@ -4680,7 +4677,7 @@ int32_t parseLimitClause(SQueryInfo* pQueryInfo, int32_t clauseIndex, SQuerySQL*
|
|||
|
||||
const char* msg0 = "soffset/offset can not be less than 0";
|
||||
const char* msg1 = "slimit/soffset only available for STable query";
|
||||
const char* msg2 = "function not supported on table";
|
||||
const char* msg2 = "functions mixed up in table query";
|
||||
const char* msg3 = "slimit/soffset can not apply to projection query";
|
||||
|
||||
// handle the limit offset value, validate the limit
|
||||
|
@ -4763,14 +4760,22 @@ int32_t parseLimitClause(SQueryInfo* pQueryInfo, int32_t clauseIndex, SQuerySQL*
|
|||
}
|
||||
|
||||
size_t size = taosArrayGetSize(pQueryInfo->exprList);
|
||||
|
||||
|
||||
bool hasTags = false;
|
||||
bool hasOtherFunc = false;
|
||||
// filter the query functions operating on "tbname" column that are not supported by normal columns.
|
||||
for (int32_t i = 0; i < size; ++i) {
|
||||
SSqlExpr* pExpr = tscSqlExprGet(pQueryInfo, i);
|
||||
if (pExpr->colInfo.colIndex == TSDB_TBNAME_COLUMN_INDEX) {
|
||||
return invalidSqlErrMsg(pQueryInfo->msg, msg2);
|
||||
if (TSDB_COL_IS_TAG(pExpr->colInfo.flag)) {
|
||||
hasTags = true;
|
||||
} else {
|
||||
hasOtherFunc = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasTags && hasOtherFunc) {
|
||||
return invalidSqlErrMsg(pQueryInfo->msg, msg2);
|
||||
}
|
||||
}
|
||||
|
||||
return TSDB_CODE_SUCCESS;
|
||||
|
@ -5571,21 +5576,9 @@ int32_t doCheckForCreateFromStable(SSqlObj* pSql, SSqlInfo* pInfo) {
|
|||
if (pList->a[i].pVar.nLen + VARSTR_HEADER_SIZE > pTagSchema[i].bytes) {
|
||||
return invalidSqlErrMsg(tscGetErrorMsgPayload(pCmd), msg3);
|
||||
}
|
||||
|
||||
ret = tVariantDump(&(pList->a[i].pVar), varDataVal(tagVal), pTagSchema[i].type);
|
||||
if (pList->a[i].pVar.nType == TSDB_DATA_TYPE_NULL) {
|
||||
if (pTagSchema[i].type == TSDB_DATA_TYPE_BINARY) {
|
||||
varDataSetLen(tagVal, sizeof(uint8_t));
|
||||
} else {
|
||||
varDataSetLen(tagVal, sizeof(uint32_t));
|
||||
}
|
||||
} else { // todo refactor
|
||||
varDataSetLen(tagVal, pList->a[i].pVar.nLen);
|
||||
}
|
||||
} else {
|
||||
ret = tVariantDump(&(pList->a[i].pVar), tagVal, pTagSchema[i].type);
|
||||
}
|
||||
|
||||
ret = tVariantDump(&(pList->a[i].pVar), tagVal, pTagSchema[i].type, true);
|
||||
if (ret != TSDB_CODE_SUCCESS) {
|
||||
return invalidSqlErrMsg(tscGetErrorMsgPayload(pCmd), msg4);
|
||||
}
|
||||
|
@ -5845,7 +5838,7 @@ int32_t doCheckForQuery(SSqlObj* pSql, SQuerySQL* pQuerySql, int32_t index) {
|
|||
pQueryInfo->window.ekey = pQueryInfo->window.ekey / 1000;
|
||||
}
|
||||
} else { // set the time rang
|
||||
pQueryInfo->window.skey = 0;
|
||||
pQueryInfo->window.skey = TSKEY_INITIAL_VAL;
|
||||
pQueryInfo->window.ekey = INT64_MAX;
|
||||
}
|
||||
|
||||
|
|
|
@ -689,7 +689,7 @@ int32_t tscLocalReducerEnvCreate(SSqlObj *pSql, tExtMemBuffer ***pMemBuffer, tOr
|
|||
|
||||
SSchema *p1 = tscGetTableColumnSchema(pTableMetaInfo->pTableMeta, pExpr->colInfo.colIndex);
|
||||
|
||||
int16_t inter = 0;
|
||||
int32_t inter = 0;
|
||||
int16_t type = -1;
|
||||
int16_t bytes = 0;
|
||||
|
||||
|
@ -1049,7 +1049,14 @@ static void doExecuteSecondaryMerge(SSqlCmd *pCmd, SLocalReducer *pLocalReducer,
|
|||
int32_t functionId = pExpr->functionId;
|
||||
if (functionId == TSDB_FUNC_TAG_DUMMY || functionId == TSDB_FUNC_TAG || functionId == TSDB_FUNC_TS_DUMMY) {
|
||||
tVariantDestroy(&pCtx->tag);
|
||||
tVariantCreateFromBinary(&pCtx->tag, pCtx->aInputElemBuf, pCtx->inputBytes, pCtx->inputType);
|
||||
char* input = pCtx->aInputElemBuf;
|
||||
|
||||
if (pCtx->inputType == TSDB_DATA_TYPE_BINARY || pCtx->inputType == TSDB_DATA_TYPE_NCHAR) {
|
||||
assert(varDataLen(input) <= pCtx->inputBytes);
|
||||
tVariantCreateFromBinary(&pCtx->tag, varDataVal(input), varDataLen(input), pCtx->inputType);
|
||||
} else {
|
||||
tVariantCreateFromBinary(&pCtx->tag, input, pCtx->inputBytes, pCtx->inputType);
|
||||
}
|
||||
}
|
||||
|
||||
pCtx->currentStage = SECONDARY_STAGE_MERGE;
|
||||
|
@ -1309,7 +1316,7 @@ static bool isAllSourcesCompleted(SLocalReducer *pLocalReducer) {
|
|||
return (pLocalReducer->numOfBuffer == pLocalReducer->numOfCompleted);
|
||||
}
|
||||
|
||||
static bool doInterpolationForCurrentGroup(SSqlObj *pSql) {
|
||||
static bool doBuildFilledResultForGroup(SSqlObj *pSql) {
|
||||
SSqlCmd *pCmd = &pSql->cmd;
|
||||
SSqlRes *pRes = &pSql->res;
|
||||
|
||||
|
@ -1347,8 +1354,8 @@ static bool doHandleLastRemainData(SSqlObj *pSql) {
|
|||
SSqlCmd *pCmd = &pSql->cmd;
|
||||
SSqlRes *pRes = &pSql->res;
|
||||
|
||||
SLocalReducer * pLocalReducer = pRes->pLocalReducer;
|
||||
SFillInfo *pFillInfo = pLocalReducer->pFillInfo;
|
||||
SLocalReducer *pLocalReducer = pRes->pLocalReducer;
|
||||
SFillInfo *pFillInfo = pLocalReducer->pFillInfo;
|
||||
|
||||
bool prevGroupCompleted = (!pLocalReducer->discard) && pLocalReducer->hasUnprocessedRow;
|
||||
|
||||
|
@ -1445,7 +1452,7 @@ int32_t tscDoLocalMerge(SSqlObj *pSql) {
|
|||
return TSDB_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
if (doInterpolationForCurrentGroup(pSql)) {
|
||||
if (doBuildFilledResultForGroup(pSql)) {
|
||||
pLocalReducer->status = TSC_LOCALREDUCE_READY; // set the flag, taos_free_result can release this result.
|
||||
return TSDB_CODE_SUCCESS;
|
||||
}
|
||||
|
@ -1464,8 +1471,7 @@ int32_t tscDoLocalMerge(SSqlObj *pSql) {
|
|||
#ifdef _DEBUG_VIEW
|
||||
printf("chosen data in pTree[0] = %d\n", pTree->pNode[0].index);
|
||||
#endif
|
||||
assert((pTree->pNode[0].index < pLocalReducer->numOfBuffer) && (pTree->pNode[0].index >= 0) &&
|
||||
tmpBuffer->num == 0);
|
||||
assert((pTree->pNode[0].index < pLocalReducer->numOfBuffer) && (pTree->pNode[0].index >= 0) && tmpBuffer->num == 0);
|
||||
|
||||
// chosen from loser tree
|
||||
SLocalDataSource *pOneDataSrc = pLocalReducer->pLocalDataSrc[pTree->pNode[0].index];
|
||||
|
|
|
@ -651,7 +651,7 @@ int tscBuildQueryMsg(SSqlObj *pSql, SSqlInfo *pInfo) {
|
|||
|
||||
pQueryMsg->order = htons(pQueryInfo->order.order);
|
||||
pQueryMsg->orderColId = htons(pQueryInfo->order.orderColId);
|
||||
pQueryMsg->fillType = htons(pQueryInfo->fillType);
|
||||
pQueryMsg->fillType = htons(pQueryInfo->fillType);
|
||||
pQueryMsg->limit = htobe64(pQueryInfo->limit.limit);
|
||||
pQueryMsg->offset = htobe64(pQueryInfo->limit.offset);
|
||||
pQueryMsg->numOfCols = htons(taosArrayGetSize(pQueryInfo->colList));
|
||||
|
@ -1287,7 +1287,7 @@ int tscBuildAlterTableMsg(SSqlObj *pSql, SSqlInfo *pInfo) {
|
|||
|
||||
pAlterTableMsg->numOfCols = htons(tscNumOfFields(pQueryInfo));
|
||||
SSchema *pSchema = pAlterTableMsg->schema;
|
||||
for (int i = 0; i < pAlterTableMsg->numOfCols; ++i) {
|
||||
for (int i = 0; i < tscNumOfFields(pQueryInfo); ++i) {
|
||||
TAOS_FIELD *pField = tscFieldInfoGetField(&pQueryInfo->fieldsInfo, i);
|
||||
|
||||
pSchema->type = pField->type;
|
||||
|
@ -1843,17 +1843,6 @@ int tscProcessTableMetaRsp(SSqlObj *pSql) {
|
|||
|
||||
size_t size = 0;
|
||||
STableMeta* pTableMeta = tscCreateTableMetaFromMsg(pMetaMsg, &size);
|
||||
|
||||
#if 0
|
||||
// if current table is created according to super table, get the table meta of super table
|
||||
if (pTableMeta->tableType == TSDB_CHILD_TABLE) {
|
||||
char id[TSDB_TABLE_ID_LEN + 1] = {0};
|
||||
strncpy(id, pMetaMsg->stableId, TSDB_TABLE_ID_LEN);
|
||||
|
||||
// NOTE: if the table meta of super table is not cached at client side yet, the pSTable is NULL
|
||||
pTableMeta->pSTable = taosCacheAcquireByName(tscCacheHandle, id);
|
||||
}
|
||||
#endif
|
||||
|
||||
// todo add one more function: taosAddDataIfNotExists();
|
||||
STableMetaInfo *pTableMetaInfo = tscGetTableMetaInfoFromCmd(&pSql->cmd, 0, 0);
|
||||
|
@ -1976,7 +1965,7 @@ int tscProcessMultiMeterMetaRsp(SSqlObj *pSql) {
|
|||
|
||||
pSql->res.code = TSDB_CODE_SUCCESS;
|
||||
pSql->res.numOfTotal = i;
|
||||
tscTrace("%p load multi-metermeta resp complete num:%d", pSql, pSql->res.numOfTotal);
|
||||
tscTrace("%p load multi-metermeta resp from complete num:%d", pSql, pSql->res.numOfTotal);
|
||||
#endif
|
||||
|
||||
return TSDB_CODE_SUCCESS;
|
||||
|
|
|
@ -284,12 +284,11 @@ int taos_query(TAOS *taos, const char *sqlstr) {
|
|||
}
|
||||
|
||||
SSqlObj* pSql = pObj->pSql;
|
||||
|
||||
size_t sqlLen = strlen(sqlstr);
|
||||
size_t sqlLen = strlen(sqlstr);
|
||||
doAsyncQuery(pObj, pSql, waitForQueryRsp, taos, sqlstr, sqlLen);
|
||||
|
||||
// wait for the callback function to post the semaphore
|
||||
sem_wait(&pSql->rspSem);
|
||||
tsem_wait(&pSql->rspSem);
|
||||
return pSql->res.code;
|
||||
}
|
||||
|
||||
|
@ -525,7 +524,7 @@ int taos_select_db(TAOS *taos, const char *db) {
|
|||
return taos_query(taos, sql);
|
||||
}
|
||||
|
||||
void taos_free_result_imp(TAOS_RES *res, int keepCmd) {
|
||||
void taos_free_result(TAOS_RES *res) {
|
||||
if (res == NULL) return;
|
||||
|
||||
SSqlObj *pSql = (SSqlObj *)res;
|
||||
|
@ -536,26 +535,23 @@ void taos_free_result_imp(TAOS_RES *res, int keepCmd) {
|
|||
|
||||
if (pSql->signature != pSql) return;
|
||||
|
||||
STscObj* pObj = pSql->pTscObj;
|
||||
if (pRes == NULL || pRes->qhandle == 0) {
|
||||
/* Query rsp is not received from vnode, so the qhandle is NULL */
|
||||
tscTrace("%p qhandle is null, abort free, fp:%p", pSql, pSql->fp);
|
||||
STscObj* pTscObj = pSql->pTscObj;
|
||||
|
||||
if (pTscObj->pSql != pSql) {
|
||||
// The semaphore can not be changed while freeing async sub query objects.
|
||||
if (pObj->pSql != pSql) {
|
||||
tscTrace("%p SqlObj is freed by app", pSql);
|
||||
tscFreeSqlObj(pSql);
|
||||
} else {
|
||||
if (keepCmd) {
|
||||
tscFreeSqlResult(pSql);
|
||||
} else {
|
||||
tscPartiallyFreeSqlObj(pSql);
|
||||
}
|
||||
tscPartiallyFreeSqlObj(pSql);
|
||||
}
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// set freeFlag to 1 in retrieve message if there are un-retrieved results
|
||||
// set freeFlag to 1 in retrieve message if there are un-retrieved results data in node
|
||||
SQueryInfo *pQueryInfo = tscGetQueryInfoDetail(&pSql->cmd, 0);
|
||||
if (pQueryInfo == NULL) {
|
||||
tscPartiallyFreeSqlObj(pSql);
|
||||
|
@ -563,6 +559,7 @@ void taos_free_result_imp(TAOS_RES *res, int keepCmd) {
|
|||
}
|
||||
|
||||
pQueryInfo->type = TSDB_QUERY_TYPE_FREE_RESOURCE;
|
||||
STscObj* pTscObj = pSql->pTscObj;
|
||||
|
||||
STableMetaInfo *pTableMetaInfo = tscGetMetaInfo(pQueryInfo, 0);
|
||||
|
||||
|
@ -579,9 +576,8 @@ void taos_free_result_imp(TAOS_RES *res, int keepCmd) {
|
|||
if ((pCmd->command == TSDB_SQL_SELECT ||
|
||||
pCmd->command == TSDB_SQL_SHOW ||
|
||||
pCmd->command == TSDB_SQL_RETRIEVE ||
|
||||
pCmd->command == TSDB_SQL_FETCH) && pRes->code == TSDB_CODE_SUCCESS &&
|
||||
((pCmd->command < TSDB_SQL_LOCAL && pRes->completed == false) ||
|
||||
(pCmd->command == TSDB_SQL_SELECT && pSql->pStream == NULL && pTableMetaInfo->pTableMeta != NULL))) {
|
||||
pCmd->command == TSDB_SQL_FETCH) && pRes->code == TSDB_CODE_SUCCESS && pRes->completed == false &&
|
||||
(pCmd->command == TSDB_SQL_SELECT && pSql->pStream == NULL && pTableMetaInfo->pTableMeta != NULL)) {
|
||||
pCmd->command = (pCmd->command > TSDB_SQL_MGMT) ? TSDB_SQL_RETRIEVE : TSDB_SQL_FETCH;
|
||||
|
||||
tscTrace("%p send msg to free qhandle in vnode, code:%d, numOfRows:%d, command:%s", pSql, pRes->code, pRes->numOfRows,
|
||||
|
@ -591,30 +587,20 @@ void taos_free_result_imp(TAOS_RES *res, int keepCmd) {
|
|||
tscProcessSql(pSql);
|
||||
|
||||
// waits for response and then goes on
|
||||
STscObj* pTscObj = pSql->pTscObj;
|
||||
if (pTscObj->pSql == pSql) {
|
||||
sem_wait(&pSql->rspSem);
|
||||
}
|
||||
} else { // if no free resource msg is sent to vnode, we free this object immediately.
|
||||
STscObj* pTscObj = pSql->pTscObj;
|
||||
|
||||
if (pTscObj->pSql != pSql) {
|
||||
tscFreeSqlObj(pSql);
|
||||
tscTrace("%p sql result is freed by app", pSql);
|
||||
} else {
|
||||
if (keepCmd) {
|
||||
tscFreeSqlResult(pSql);
|
||||
tscTrace("%p sql result is freed while sql command is kept", pSql);
|
||||
} else {
|
||||
tscPartiallyFreeSqlObj(pSql);
|
||||
tscTrace("%p sql result is freed by app", pSql);
|
||||
}
|
||||
tscPartiallyFreeSqlObj(pSql);
|
||||
tscTrace("%p sql result is freed by app", pSql);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void taos_free_result(TAOS_RES *res) { taos_free_result_imp(res, 0); }
|
||||
|
||||
// todo should not be used in async query
|
||||
int taos_errno(TAOS *taos) {
|
||||
STscObj *pObj = (STscObj *)taos;
|
||||
|
|
|
@ -1084,7 +1084,7 @@ int32_t tscLaunchJoinSubquery(SSqlObj *pSql, int16_t tableIndex, SJoinSupporter
|
|||
|
||||
int16_t bytes = 0;
|
||||
int16_t type = 0;
|
||||
int16_t inter = 0;
|
||||
int32_t inter = 0;
|
||||
|
||||
getResultDataInfo(s.type, s.bytes, TSDB_FUNC_TID_TAG, 0, &type, &bytes, &inter, 0, 0);
|
||||
|
||||
|
@ -1770,6 +1770,8 @@ int32_t tscHandleMultivnodeInsert(SSqlObj *pSql) {
|
|||
*/
|
||||
pNew->fetchFp = pNew->fp;
|
||||
pSql->pSubs[i] = pNew;
|
||||
pNew->fetchFp = pNew->fp;
|
||||
|
||||
tscTrace("%p sub:%p create subObj success. orderOfSub:%d", pSql, pNew, i);
|
||||
}
|
||||
|
||||
|
|
|
@ -421,7 +421,6 @@ void tscFreeSqlObj(SSqlObj* pSql) {
|
|||
|
||||
memset(pCmd->payload, 0, (size_t)pCmd->allocSize);
|
||||
tfree(pCmd->payload);
|
||||
|
||||
pCmd->allocSize = 0;
|
||||
|
||||
tfree(pSql->sqlstr);
|
||||
|
@ -1033,7 +1032,7 @@ SSqlExpr* tscSqlExprUpdate(SQueryInfo* pQueryInfo, int32_t index, int16_t functi
|
|||
return pExpr;
|
||||
}
|
||||
|
||||
int32_t tscSqlExprNumOfExprs(SQueryInfo* pQueryInfo) {
|
||||
size_t tscSqlExprNumOfExprs(SQueryInfo* pQueryInfo) {
|
||||
return taosArrayGetSize(pQueryInfo->exprList);
|
||||
}
|
||||
|
||||
|
@ -1352,7 +1351,7 @@ bool tscValidateColumnId(STableMetaInfo* pTableMetaInfo, int32_t colId) {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (colId == -1 && UTIL_TABLE_IS_SUPER_TABLE(pTableMetaInfo)) {
|
||||
if (colId == TSDB_TBNAME_COLUMN_INDEX) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1768,11 +1767,12 @@ SSqlObj* createSubqueryObj(SSqlObj* pSql, int16_t tableIndex, void (*fp)(), void
|
|||
pNewQueryInfo->limit = pQueryInfo->limit;
|
||||
pNewQueryInfo->slimit = pQueryInfo->slimit;
|
||||
pNewQueryInfo->order = pQueryInfo->order;
|
||||
pNewQueryInfo->clauseLimit = pQueryInfo->clauseLimit;
|
||||
pNewQueryInfo->pTableMetaInfo = NULL;
|
||||
pNewQueryInfo->tsBuf = NULL;
|
||||
pNewQueryInfo->fillType = pQueryInfo->fillType;
|
||||
pNewQueryInfo->fillVal = NULL;
|
||||
pNewQueryInfo->clauseLimit = pQueryInfo->clauseLimit;
|
||||
pNewQueryInfo->numOfTables = 0;
|
||||
pNewQueryInfo->tsBuf = NULL;
|
||||
pNewQueryInfo->pTableMetaInfo = NULL;
|
||||
|
||||
pNewQueryInfo->groupbyExpr = pQueryInfo->groupbyExpr;
|
||||
if (pQueryInfo->groupbyExpr.columnInfo != NULL) {
|
||||
|
@ -1864,7 +1864,7 @@ SSqlObj* createSubqueryObj(SSqlObj* pSql, int16_t tableIndex, void (*fp)(), void
|
|||
}
|
||||
|
||||
if (pFinalInfo->pTableMeta == NULL) {
|
||||
tscError("%p new subquery failed for get pMeterMeta is NULL from cache", pSql);
|
||||
tscError("%p new subquery failed for get tableMeta is NULL from cache", pSql);
|
||||
tscFreeSqlObj(pNew);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -2011,7 +2011,7 @@ bool hasMoreVnodesToTry(SSqlObj* pSql) {
|
|||
STableMetaInfo* pTableMetaInfo = tscGetMetaInfo(pQueryInfo, 0);
|
||||
assert(pRes->completed);
|
||||
|
||||
// for normal table, do not try any more if result are exhausted
|
||||
// for normal table, no need to try any more if results are all retrieved from one vnode
|
||||
if (!UTIL_TABLE_IS_SUPER_TABLE(pTableMetaInfo) || (pTableMetaInfo->vgroupList == NULL)) {
|
||||
return false;
|
||||
}
|
||||
|
@ -2037,7 +2037,7 @@ void tscTryQueryNextVnode(SSqlObj* pSql, __async_cb_func_t fp) {
|
|||
|
||||
int32_t totalVgroups = pTableMetaInfo->vgroupList->numOfVgroups;
|
||||
while (++pTableMetaInfo->vgroupIndex < totalVgroups) {
|
||||
tscTrace("%p current vnode:%d exhausted, try next:%d. total vnode:%d. current numOfRes:%d", pSql,
|
||||
tscTrace("%p results from vgroup index:%d completed, try next:%d. total vgroups:%d. current numOfRes:%d", pSql,
|
||||
pTableMetaInfo->vgroupIndex - 1, pTableMetaInfo->vgroupIndex, totalVgroups, pRes->numOfClauseTotal);
|
||||
|
||||
/*
|
||||
|
@ -2121,7 +2121,7 @@ void tscGetResultColumnChr(SSqlRes* pRes, SFieldInfo* pFieldInfo, int32_t column
|
|||
int32_t type = pInfo->pSqlExpr->resType;
|
||||
int32_t bytes = pInfo->pSqlExpr->resBytes;
|
||||
|
||||
char* pData = ((char*) pRes->data) + pInfo->pSqlExpr->offset * pRes->numOfRows + bytes * pRes->row;
|
||||
char* pData = pRes->data + pInfo->pSqlExpr->offset * pRes->numOfRows + bytes * pRes->row;
|
||||
|
||||
if (type == TSDB_DATA_TYPE_NCHAR || type == TSDB_DATA_TYPE_BINARY) {
|
||||
int32_t realLen = varDataLen(pData);
|
||||
|
@ -2134,7 +2134,7 @@ void tscGetResultColumnChr(SSqlRes* pRes, SFieldInfo* pFieldInfo, int32_t column
|
|||
}
|
||||
|
||||
if (realLen < pInfo->pSqlExpr->resBytes - VARSTR_HEADER_SIZE) { // todo refactor
|
||||
*(char*) (pData + realLen + VARSTR_HEADER_SIZE) = 0;
|
||||
*(pData + realLen + VARSTR_HEADER_SIZE) = 0;
|
||||
}
|
||||
|
||||
pRes->length[columnIndex] = realLen;
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "talgo.h"
|
||||
#include "taosdef.h"
|
||||
#include "tutil.h"
|
||||
|
||||
|
@ -26,19 +27,24 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define STR_TO_VARSTR(x, str) do {VarDataLenT __len = strlen(str); \
|
||||
*(VarDataLenT*)(x) = __len; \
|
||||
strncpy(varDataVal(x), (str), __len);} while(0);
|
||||
#define STR_TO_VARSTR(x, str) \
|
||||
do { \
|
||||
VarDataLenT __len = strlen(str); \
|
||||
*(VarDataLenT *)(x) = __len; \
|
||||
strncpy(varDataVal(x), (str), __len); \
|
||||
} while (0);
|
||||
|
||||
#define STR_WITH_MAXSIZE_TO_VARSTR(x, str, _maxs) do {\
|
||||
char* _e = stpncpy(varDataVal(x), (str), (_maxs));\
|
||||
varDataSetLen(x, (_e - (x) - VARSTR_HEADER_SIZE));\
|
||||
} while(0)
|
||||
#define STR_WITH_MAXSIZE_TO_VARSTR(x, str, _maxs) \
|
||||
do { \
|
||||
char *_e = stpncpy(varDataVal(x), (str), (_maxs)); \
|
||||
varDataSetLen(x, (_e - (x)-VARSTR_HEADER_SIZE)); \
|
||||
} while (0)
|
||||
|
||||
#define STR_WITH_SIZE_TO_VARSTR(x, str, _size) do {\
|
||||
*(VarDataLenT*)(x) = (_size); \
|
||||
strncpy(varDataVal(x), (str), (_size));\
|
||||
} while(0);
|
||||
#define STR_WITH_SIZE_TO_VARSTR(x, str, _size) \
|
||||
do { \
|
||||
*(VarDataLenT *)(x) = (_size); \
|
||||
strncpy(varDataVal(x), (str), (_size)); \
|
||||
} while (0);
|
||||
|
||||
// ----------------- TSDB COLUMN DEFINITION
|
||||
typedef struct {
|
||||
|
@ -60,7 +66,7 @@ typedef struct {
|
|||
|
||||
// ----------------- TSDB SCHEMA DEFINITION
|
||||
typedef struct {
|
||||
int totalCols; // Total columns allocated
|
||||
int version; // version
|
||||
int numOfCols; // Number of columns appended
|
||||
int tlen; // maximum length of a SDataRow without the header part
|
||||
int flen; // First part length in a SDataRow after the header part
|
||||
|
@ -68,19 +74,48 @@ typedef struct {
|
|||
} STSchema;
|
||||
|
||||
#define schemaNCols(s) ((s)->numOfCols)
|
||||
#define schemaTotalCols(s) ((s)->totalCols)
|
||||
#define schemaVersion(s) ((s)->version)
|
||||
#define schemaTLen(s) ((s)->tlen)
|
||||
#define schemaFLen(s) ((s)->flen)
|
||||
#define schemaColAt(s, i) ((s)->columns + i)
|
||||
#define tdFreeSchema(s) tfree((s))
|
||||
|
||||
STSchema *tdNewSchema(int32_t nCols);
|
||||
#define tdFreeSchema(s) tfree((s))
|
||||
int tdSchemaAddCol(STSchema *pSchema, int8_t type, int16_t colId, int32_t bytes);
|
||||
STSchema *tdDupSchema(STSchema *pSchema);
|
||||
int tdGetSchemaEncodeSize(STSchema *pSchema);
|
||||
void * tdEncodeSchema(void *dst, STSchema *pSchema);
|
||||
STSchema *tdDecodeSchema(void **psrc);
|
||||
|
||||
static FORCE_INLINE int comparColId(const void *key1, const void *key2) {
|
||||
if (*(int16_t *)key1 > ((STColumn *)key2)->colId) {
|
||||
return 1;
|
||||
} else if (*(int16_t *)key1 < ((STColumn *)key2)->colId) {
|
||||
return -1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static FORCE_INLINE STColumn *tdGetColOfID(STSchema *pSchema, int16_t colId) {
|
||||
void *ptr = bsearch(&colId, (void *)pSchema->columns, schemaNCols(pSchema), sizeof(STColumn), comparColId);
|
||||
if (ptr == NULL) return NULL;
|
||||
return (STColumn *)ptr;
|
||||
}
|
||||
|
||||
// ----------------- SCHEMA BUILDER DEFINITION
|
||||
typedef struct {
|
||||
int tCols;
|
||||
int nCols;
|
||||
int tlen;
|
||||
int flen;
|
||||
int version;
|
||||
STColumn *columns;
|
||||
} STSchemaBuilder;
|
||||
|
||||
int tdInitTSchemaBuilder(STSchemaBuilder *pBuilder, int32_t version);
|
||||
void tdDestroyTSchemaBuilder(STSchemaBuilder *pBuilder);
|
||||
void tdResetTSchemaBuilder(STSchemaBuilder *pBuilder, int32_t version);
|
||||
int tdAddColToSchema(STSchemaBuilder *pBuilder, int8_t type, int16_t colId, int32_t bytes);
|
||||
STSchema *tdGetSchemaFromBuilder(STSchemaBuilder *pBuilder);
|
||||
|
||||
// ----------------- Data row structure
|
||||
|
||||
/* A data row, the format is like below:
|
||||
|
@ -188,12 +223,11 @@ static FORCE_INLINE int32_t dataColGetNEleLen(SDataCol *pDataCol, int rows) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
typedef struct {
|
||||
int maxRowSize;
|
||||
int maxCols; // max number of columns
|
||||
int maxPoints; // max number of points
|
||||
int bufSize;
|
||||
int maxRowSize;
|
||||
int maxCols; // max number of columns
|
||||
int maxPoints; // max number of points
|
||||
int bufSize;
|
||||
|
||||
int numOfRows;
|
||||
int numOfCols; // Total number of cols
|
||||
|
@ -213,62 +247,102 @@ void tdInitDataCols(SDataCols *pCols, STSchema *pSchema);
|
|||
SDataCols *tdDupDataCols(SDataCols *pCols, bool keepData);
|
||||
void tdFreeDataCols(SDataCols *pCols);
|
||||
void tdAppendDataRowToDataCol(SDataRow row, SDataCols *pCols);
|
||||
void tdPopDataColsPoints(SDataCols *pCols, int pointsToPop); //!!!!
|
||||
void tdPopDataColsPoints(SDataCols *pCols, int pointsToPop); //!!!!
|
||||
int tdMergeDataCols(SDataCols *target, SDataCols *src, int rowsToMerge);
|
||||
void tdMergeTwoDataCols(SDataCols *target, SDataCols *src1, int *iter1, SDataCols *src2, int *iter2, int tRows);
|
||||
|
||||
|
||||
// ----------------- Tag row structure
|
||||
|
||||
/* A tag row, the format is like below:
|
||||
+----------+----------------------------------------------------------------+
|
||||
| STagRow | STagCol | STagCol | STagCol | STagCol | ...| STagCol | STagCol |
|
||||
+----------+----------------------------------------------------------------+
|
||||
|
||||
pData
|
||||
+----------+----------------------------------------------------------------+
|
||||
| value 1 | value 2 | value 3 | value 4 | ....|value n |
|
||||
+----------+----------------------------------------------------------------+
|
||||
|
||||
// ----------------- K-V data row structure
|
||||
/*
|
||||
* +----------+----------+---------------------------------+---------------------------------+
|
||||
* | int16_t | int16_t | | |
|
||||
* +----------+----------+---------------------------------+---------------------------------+
|
||||
* | len | ncols | cols index | data part |
|
||||
* +----------+----------+---------------------------------+---------------------------------+
|
||||
*/
|
||||
|
||||
|
||||
#define TD_TAG_ROW_HEAD_SIZE sizeof(int16_t)
|
||||
|
||||
#define tagRowNum(r) (*(int16_t *)(r))
|
||||
#define tagRowArray(r) POINTER_SHIFT(r, TD_TAG_ROW_HEAD_SIZE)
|
||||
//#define dataRowKey(r) (*(TSKEY *)(dataRowTuple(r)))
|
||||
//#define dataRowSetLen(r, l) (dataRowLen(r) = (l))
|
||||
//#define dataRowCpy(dst, r) memcpy((dst), (r), dataRowLen(r))
|
||||
//#define dataRowMaxBytesFromSchema(s) (schemaTLen(s) + TD_DATA_ROW_HEAD_SIZE)
|
||||
typedef void *SKVRow;
|
||||
|
||||
typedef struct {
|
||||
int16_t colId; // column ID
|
||||
int16_t colType;
|
||||
uint16_t offset; //to store value for numeric col or offset for binary/Nchar
|
||||
} STagCol;
|
||||
int16_t colId;
|
||||
int16_t offset;
|
||||
} SColIdx;
|
||||
|
||||
#define TD_KV_ROW_HEAD_SIZE 2 * sizeof(int16_t)
|
||||
|
||||
#define kvRowLen(r) (*(int16_t *)(r))
|
||||
#define kvRowNCols(r) (*(int16_t *)POINTER_SHIFT(r, sizeof(int16_t)))
|
||||
#define kvRowSetLen(r, len) kvRowLen(r) = (len)
|
||||
#define kvRowSetNCols(r, n) kvRowNCols(r) = (n)
|
||||
#define kvRowColIdx(r) (SColIdx *)POINTER_SHIFT(r, TD_KV_ROW_HEAD_SIZE)
|
||||
#define kvRowValues(r) POINTER_SHIFT(r, TD_KV_ROW_HEAD_SIZE + sizeof(SColIdx) * kvRowNCols(r))
|
||||
#define kvRowCpy(dst, r) memcpy((dst), (r), kvRowLen(r))
|
||||
#define kvRowColVal(r, colIdx) POINTER_SHIFT(kvRowValues(r), (colIdx)->offset)
|
||||
#define kvRowColIdxAt(r, i) (kvRowColIdx(r) + (i))
|
||||
#define kvRowFree(r) tfree(r)
|
||||
|
||||
SKVRow tdKVRowDup(SKVRow row);
|
||||
SKVRow tdSetKVRowDataOfCol(SKVRow row, int16_t colId, int8_t type, void *value);
|
||||
void * tdEncodeKVRow(void *buf, SKVRow row);
|
||||
void * tdDecodeKVRow(void *buf, SKVRow *row);
|
||||
|
||||
static FORCE_INLINE int comparTagId(const void *key1, const void *key2) {
|
||||
if (*(int16_t *)key1 > ((SColIdx *)key2)->colId) {
|
||||
return 1;
|
||||
} else if (*(int16_t *)key1 < ((SColIdx *)key2)->colId) {
|
||||
return -1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static FORCE_INLINE void *tdGetKVRowValOfCol(SKVRow row, int16_t colId) {
|
||||
void *ret = taosbsearch(&colId, kvRowColIdx(row), kvRowNCols(row), sizeof(SColIdx), comparTagId, TD_EQ);
|
||||
if (ret == NULL) return NULL;
|
||||
return kvRowColVal(row, (SColIdx *)ret);
|
||||
}
|
||||
|
||||
// ----------------- K-V data row builder
|
||||
typedef struct {
|
||||
int32_t len;
|
||||
void * pData; // Space to store the tag value
|
||||
uint16_t dataLen;
|
||||
int16_t ncols; // Total columns allocated
|
||||
STagCol tagCols[];
|
||||
} STagRow;
|
||||
int16_t tCols;
|
||||
int16_t nCols;
|
||||
SColIdx *pColIdx;
|
||||
int16_t alloc;
|
||||
int16_t size;
|
||||
void * buf;
|
||||
} SKVRowBuilder;
|
||||
|
||||
int tdInitKVRowBuilder(SKVRowBuilder *pBuilder);
|
||||
void tdDestroyKVRowBuilder(SKVRowBuilder *pBuilder);
|
||||
void tdResetKVRowBuilder(SKVRowBuilder *pBuilder);
|
||||
SKVRow tdGetKVRowFromBuilder(SKVRowBuilder *pBuilder);
|
||||
|
||||
#define tagColSize(r) (sizeof(STagCol) + r.colLen)
|
||||
static FORCE_INLINE int tdAddColToKVRow(SKVRowBuilder *pBuilder, int16_t colId, int8_t type, void *value) {
|
||||
ASSERT(pBuilder->nCols == 0 || colId > pBuilder->pColIdx[pBuilder->nCols - 1].colId);
|
||||
|
||||
int tdSetTagCol(SDataRow row, void *value, int16_t len, int8_t type, int16_t colId); //insert tag value and update all the information
|
||||
int tdDeleteTagCol(SDataRow row, int16_t colId); // delete tag value and update all the information
|
||||
void * tdQueryTagByID(SDataRow row, int16_t colId, int16_t *type); //if find tag, 0, else return -1;
|
||||
int tdAppendTagColVal(SDataRow row, void *value, int8_t type, int32_t bytes, int16_t colId);
|
||||
SDataRow tdTagRowDup(SDataRow row);
|
||||
void tdFreeTagRow(SDataRow row);
|
||||
SDataRow tdTagRowDecode(SDataRow row);
|
||||
int tdTagRowCpy(SDataRow dst, SDataRow src);
|
||||
void * tdNewTagRowFromSchema(STSchema *pSchema, int16_t numofTags);
|
||||
STSchema *tdGetSchemaFromData(SDataRow *row);
|
||||
if (pBuilder->nCols >= pBuilder->tCols) {
|
||||
pBuilder->tCols *= 2;
|
||||
pBuilder->pColIdx = (SColIdx *)realloc((void *)(pBuilder->pColIdx), sizeof(SColIdx) * pBuilder->tCols);
|
||||
if (pBuilder->pColIdx == NULL) return -1;
|
||||
}
|
||||
|
||||
pBuilder->pColIdx[pBuilder->nCols].colId = colId;
|
||||
pBuilder->pColIdx[pBuilder->nCols].offset = pBuilder->size;
|
||||
|
||||
pBuilder->nCols++;
|
||||
|
||||
int tlen = IS_VAR_DATA_TYPE(type) ? varDataTLen(value) : TYPE_BYTES[type];
|
||||
if (tlen > pBuilder->alloc - pBuilder->size) {
|
||||
while (tlen > pBuilder->alloc - pBuilder->size) {
|
||||
pBuilder->alloc *= 2;
|
||||
}
|
||||
pBuilder->buf = realloc(pBuilder->buf, pBuilder->alloc);
|
||||
if (pBuilder->buf == NULL) return -1;
|
||||
}
|
||||
|
||||
memcpy(POINTER_SHIFT(pBuilder->buf, pBuilder->size), value, tlen);
|
||||
pBuilder->size += tlen;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -49,7 +49,7 @@ extern int32_t tsTotalMemoryMB;
|
|||
extern int32_t tsVersion;
|
||||
|
||||
extern int32_t tscEmbedded;
|
||||
extern int64_t tsMsPerDay[2];
|
||||
extern int64_t tsMsPerDay[3];
|
||||
|
||||
extern char tsFirst[];
|
||||
extern char tsSecond[];
|
||||
|
@ -94,6 +94,10 @@ extern int32_t tsMaxTables;
|
|||
extern char tsDefaultDB[];
|
||||
extern char tsDefaultUser[];
|
||||
extern char tsDefaultPass[];
|
||||
|
||||
extern char tsMqttBrokerAddress[];
|
||||
extern char tsMqttBrokerClientId[];
|
||||
|
||||
extern int32_t tsMaxConnections;
|
||||
|
||||
extern int32_t tsBalanceInterval;
|
||||
|
|
|
@ -13,96 +13,30 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "tdataformat.h"
|
||||
#include "wchar.h"
|
||||
#include "talgo.h"
|
||||
|
||||
/**
|
||||
* Create a SSchema object with nCols columns
|
||||
* ASSUMPTIONS: VALID PARAMETERS
|
||||
*
|
||||
* @param nCols number of columns the schema has
|
||||
*
|
||||
* @return a STSchema object for success
|
||||
* NULL for failure
|
||||
*/
|
||||
STSchema *tdNewSchema(int32_t nCols) {
|
||||
int32_t size = sizeof(STSchema) + sizeof(STColumn) * nCols;
|
||||
|
||||
STSchema *pSchema = (STSchema *)calloc(1, size);
|
||||
if (pSchema == NULL) return NULL;
|
||||
|
||||
pSchema->numOfCols = 0;
|
||||
pSchema->totalCols = nCols;
|
||||
pSchema->flen = 0;
|
||||
pSchema->tlen = 0;
|
||||
|
||||
return pSchema;
|
||||
}
|
||||
|
||||
/**
|
||||
* Append a column to the schema
|
||||
*/
|
||||
int tdSchemaAddCol(STSchema *pSchema, int8_t type, int16_t colId, int32_t bytes) {
|
||||
if (!isValidDataType(type, 0) || pSchema->numOfCols >= pSchema->totalCols) return -1;
|
||||
|
||||
STColumn *pCol = schemaColAt(pSchema, schemaNCols(pSchema));
|
||||
colSetType(pCol, type);
|
||||
colSetColId(pCol, colId);
|
||||
if (schemaNCols(pSchema) == 0) {
|
||||
colSetOffset(pCol, 0);
|
||||
} else {
|
||||
STColumn *pTCol = schemaColAt(pSchema, schemaNCols(pSchema)-1);
|
||||
colSetOffset(pCol, pTCol->offset + TYPE_BYTES[pTCol->type]);
|
||||
}
|
||||
switch (type) {
|
||||
case TSDB_DATA_TYPE_BINARY:
|
||||
case TSDB_DATA_TYPE_NCHAR:
|
||||
colSetBytes(pCol, bytes); // Set as maximum bytes
|
||||
pSchema->tlen += (TYPE_BYTES[type] + sizeof(VarDataLenT) + bytes);
|
||||
break;
|
||||
default:
|
||||
colSetBytes(pCol, TYPE_BYTES[type]);
|
||||
pSchema->tlen += TYPE_BYTES[type];
|
||||
break;
|
||||
}
|
||||
|
||||
pSchema->numOfCols++;
|
||||
pSchema->flen += TYPE_BYTES[type];
|
||||
|
||||
ASSERT(pCol->offset < pSchema->flen);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#include "wchar.h"
|
||||
|
||||
/**
|
||||
* Duplicate the schema and return a new object
|
||||
*/
|
||||
STSchema *tdDupSchema(STSchema *pSchema) {
|
||||
STSchema *tSchema = tdNewSchema(schemaNCols(pSchema));
|
||||
|
||||
int tlen = sizeof(STSchema) + sizeof(STColumn) * schemaNCols(pSchema);
|
||||
STSchema *tSchema = (STSchema *)malloc(tlen);
|
||||
if (tSchema == NULL) return NULL;
|
||||
|
||||
int32_t size = sizeof(STSchema) + sizeof(STColumn) * schemaNCols(pSchema);
|
||||
memcpy((void *)tSchema, (void *)pSchema, size);
|
||||
memcpy((void *)tSchema, (void *)pSchema, tlen);
|
||||
|
||||
return tSchema;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the size of encoded schema
|
||||
*/
|
||||
int tdGetSchemaEncodeSize(STSchema *pSchema) {
|
||||
return T_MEMBER_SIZE(STSchema, totalCols) +
|
||||
schemaNCols(pSchema) *
|
||||
(T_MEMBER_SIZE(STColumn, type) + T_MEMBER_SIZE(STColumn, colId) + T_MEMBER_SIZE(STColumn, bytes));
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode a schema to dst, and return the next pointer
|
||||
*/
|
||||
void *tdEncodeSchema(void *dst, STSchema *pSchema) {
|
||||
ASSERT(pSchema->numOfCols == pSchema->totalCols);
|
||||
|
||||
T_APPEND_MEMBER(dst, pSchema, STSchema, totalCols);
|
||||
T_APPEND_MEMBER(dst, pSchema, STSchema, version);
|
||||
T_APPEND_MEMBER(dst, pSchema, STSchema, numOfCols);
|
||||
for (int i = 0; i < schemaNCols(pSchema); i++) {
|
||||
STColumn *pCol = schemaColAt(pSchema, i);
|
||||
T_APPEND_MEMBER(dst, pCol, STColumn, type);
|
||||
|
@ -118,11 +52,14 @@ void *tdEncodeSchema(void *dst, STSchema *pSchema) {
|
|||
*/
|
||||
STSchema *tdDecodeSchema(void **psrc) {
|
||||
int totalCols = 0;
|
||||
int version = 0;
|
||||
STSchemaBuilder schemaBuilder = {0};
|
||||
|
||||
T_READ_MEMBER(*psrc, int, version);
|
||||
T_READ_MEMBER(*psrc, int, totalCols);
|
||||
|
||||
STSchema *pSchema = tdNewSchema(totalCols);
|
||||
if (pSchema == NULL) return NULL;
|
||||
if (tdInitTSchemaBuilder(&schemaBuilder, version) < 0) return NULL;
|
||||
|
||||
for (int i = 0; i < totalCols; i++) {
|
||||
int8_t type = 0;
|
||||
int16_t colId = 0;
|
||||
|
@ -131,9 +68,91 @@ STSchema *tdDecodeSchema(void **psrc) {
|
|||
T_READ_MEMBER(*psrc, int16_t, colId);
|
||||
T_READ_MEMBER(*psrc, int32_t, bytes);
|
||||
|
||||
tdSchemaAddCol(pSchema, type, colId, bytes);
|
||||
if (tdAddColToSchema(&schemaBuilder, type, colId, bytes) < 0) {
|
||||
tdDestroyTSchemaBuilder(&schemaBuilder);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
STSchema *pSchema = tdGetSchemaFromBuilder(&schemaBuilder);
|
||||
tdDestroyTSchemaBuilder(&schemaBuilder);
|
||||
return pSchema;
|
||||
}
|
||||
|
||||
int tdInitTSchemaBuilder(STSchemaBuilder *pBuilder, int32_t version) {
|
||||
if (pBuilder == NULL) return -1;
|
||||
|
||||
pBuilder->tCols = 256;
|
||||
pBuilder->columns = (STColumn *)malloc(sizeof(STColumn) * pBuilder->tCols);
|
||||
if (pBuilder->columns == NULL) return -1;
|
||||
|
||||
tdResetTSchemaBuilder(pBuilder, version);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void tdDestroyTSchemaBuilder(STSchemaBuilder *pBuilder) {
|
||||
if (pBuilder) {
|
||||
tfree(pBuilder->columns);
|
||||
}
|
||||
}
|
||||
|
||||
void tdResetTSchemaBuilder(STSchemaBuilder *pBuilder, int32_t version) {
|
||||
pBuilder->nCols = 0;
|
||||
pBuilder->tlen = 0;
|
||||
pBuilder->flen = 0;
|
||||
pBuilder->version = version;
|
||||
}
|
||||
|
||||
int tdAddColToSchema(STSchemaBuilder *pBuilder, int8_t type, int16_t colId, int32_t bytes) {
|
||||
if (!isValidDataType(type, 0)) return -1;
|
||||
|
||||
if (pBuilder->nCols >= pBuilder->tCols) {
|
||||
pBuilder->tCols *= 2;
|
||||
pBuilder->columns = (STColumn *)realloc(pBuilder->columns, sizeof(STColumn) * pBuilder->tCols);
|
||||
if (pBuilder->columns == NULL) return -1;
|
||||
}
|
||||
|
||||
STColumn *pCol = &(pBuilder->columns[pBuilder->nCols]);
|
||||
colSetType(pCol, type);
|
||||
colSetColId(pCol, colId);
|
||||
if (pBuilder->nCols == 0) {
|
||||
colSetOffset(pCol, 0);
|
||||
} else {
|
||||
STColumn *pTCol = &(pBuilder->columns[pBuilder->nCols-1]);
|
||||
colSetOffset(pCol, pTCol->offset + TYPE_BYTES[pTCol->type]);
|
||||
}
|
||||
|
||||
if (IS_VAR_DATA_TYPE(type)) {
|
||||
colSetBytes(pCol, bytes);
|
||||
pBuilder->tlen += (TYPE_BYTES[type] + sizeof(VarDataLenT) + bytes);
|
||||
} else {
|
||||
colSetBytes(pCol, TYPE_BYTES[type]);
|
||||
pBuilder->tlen += TYPE_BYTES[type];
|
||||
}
|
||||
|
||||
pBuilder->nCols++;
|
||||
pBuilder->flen += TYPE_BYTES[type];
|
||||
|
||||
ASSERT(pCol->offset < pBuilder->flen);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
STSchema *tdGetSchemaFromBuilder(STSchemaBuilder *pBuilder) {
|
||||
if (pBuilder->nCols <= 0) return NULL;
|
||||
|
||||
int tlen = sizeof(STSchema) + sizeof(STColumn) * pBuilder->nCols;
|
||||
|
||||
STSchema *pSchema = (STSchema *)malloc(tlen);
|
||||
if (pSchema == NULL) return NULL;
|
||||
|
||||
schemaVersion(pSchema) = pBuilder->version;
|
||||
schemaNCols(pSchema) = pBuilder->nCols;
|
||||
schemaTLen(pSchema) = pBuilder->tlen;
|
||||
schemaFLen(pSchema) = pBuilder->flen;
|
||||
|
||||
memcpy(schemaColAt(pSchema, 0), pBuilder->columns, sizeof(STColumn) * pBuilder->nCols);
|
||||
|
||||
return pSchema;
|
||||
}
|
||||
|
||||
|
@ -152,151 +171,6 @@ SDataRow tdNewDataRowFromSchema(STSchema *pSchema) {
|
|||
return row;
|
||||
}
|
||||
|
||||
int tdSetTagCol(SDataRow row, void *value, int16_t len, int8_t type, int16_t colId){ //insert/update tag value and update all the information
|
||||
ASSERT(((STagRow *)row)->pData != NULL);
|
||||
//STagCol * stCol = tdQueryTagColByID()
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
int tdDeleteTagCol(SDataRow row, int16_t colId){ // delete tag value and update all the information
|
||||
//todo
|
||||
return 0;
|
||||
};
|
||||
|
||||
static int compTagId(const void *key1, const void *key2) {
|
||||
if (((STagCol *)key1)->colId > ((STagCol *)key2)->colId) {
|
||||
return 1;
|
||||
} else if (((STagCol *)key1)->colId == ((STagCol *)key2)->colId) {
|
||||
return 0;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find tag structure by colId, if find, return tag structure, else return NULL;
|
||||
*/
|
||||
STagCol * tdQueryTagColByID(SDataRow row, int16_t colId, int flags) { //if find tag, 0, else return -1;
|
||||
ASSERT(((STagRow *)row)->pData != NULL);
|
||||
STagCol *pBase = ((STagRow *)row)->tagCols;
|
||||
int16_t nCols = ((STagRow *)row)->ncols;
|
||||
STagCol key = {colId,0,0};
|
||||
STagCol * stCol = taosbsearch(&key, pBase, nCols, sizeof(STagCol), compTagId, flags);
|
||||
return stCol;
|
||||
};
|
||||
|
||||
/**
|
||||
* Find tag value by colId, if find, return tag value, else return NULL;
|
||||
*/
|
||||
void * tdQueryTagByID(SDataRow row, int16_t colId, int16_t *type) {
|
||||
ASSERT(((STagRow *)row)->pData != NULL);
|
||||
STagCol *pBase = ((STagRow *)row)->tagCols;
|
||||
int16_t nCols = ((STagRow *)row)->ncols;
|
||||
STagCol key = {colId,0,0};
|
||||
STagCol * stCol = taosbsearch(&key, pBase, nCols, sizeof(STagCol), compTagId, TD_EQ);
|
||||
if (NULL == stCol) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void * pData = ((STagRow *)row)->pData;
|
||||
*type = stCol->colType;
|
||||
|
||||
return pData + stCol->offset;
|
||||
};
|
||||
|
||||
int tdAppendTagColVal(SDataRow row, void *value, int8_t type, int32_t bytes, int16_t colId){
|
||||
ASSERT(value != NULL);
|
||||
//ASSERT(bytes-2 == varDataTLen(value));
|
||||
ASSERT(row != NULL);
|
||||
STagRow *pTagrow = row;
|
||||
pTagrow->tagCols[pTagrow->ncols].colId = colId;
|
||||
pTagrow->tagCols[pTagrow->ncols].colType = type;
|
||||
pTagrow->tagCols[pTagrow->ncols].offset = pTagrow->dataLen;
|
||||
|
||||
switch (type) {
|
||||
case TSDB_DATA_TYPE_BINARY:
|
||||
case TSDB_DATA_TYPE_NCHAR:
|
||||
memcpy((char *)pTagrow->pData + pTagrow->dataLen, value, varDataTLen(value));
|
||||
pTagrow->dataLen += varDataTLen(value);
|
||||
break;
|
||||
default:
|
||||
memcpy((char *)pTagrow->pData + pTagrow->dataLen, value, TYPE_BYTES[type]);
|
||||
pTagrow->dataLen += TYPE_BYTES[type];
|
||||
break;
|
||||
}
|
||||
|
||||
pTagrow->ncols++;
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
void * tdNewTagRowFromSchema(STSchema *pSchema, int16_t numofTags) {
|
||||
int32_t size = sizeof(STagRow) + numofTags * sizeof(STagCol);
|
||||
|
||||
STagRow *row = malloc(size);
|
||||
if (row == NULL) return NULL;
|
||||
|
||||
int32_t datasize = pSchema->tlen;
|
||||
row->pData = malloc(datasize);
|
||||
if (NULL == row->pData) {
|
||||
free(row);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
row->len = size;
|
||||
row->dataLen = 0;
|
||||
row->ncols = 0;
|
||||
return row;
|
||||
}
|
||||
/**
|
||||
* free tag row
|
||||
*/
|
||||
|
||||
void tdFreeTagRow(SDataRow row) {
|
||||
if (row) {
|
||||
free(((STagRow *)row)->pData);
|
||||
free(row);
|
||||
}
|
||||
}
|
||||
|
||||
SDataRow tdTagRowDup(SDataRow row) {
|
||||
STagRow *trow = malloc(dataRowLen(row));
|
||||
if (trow == NULL) return NULL;
|
||||
|
||||
dataRowCpy(trow, row);
|
||||
trow->pData = malloc(trow->dataLen);
|
||||
if (NULL == trow->pData) {
|
||||
free(trow);
|
||||
return NULL;
|
||||
}
|
||||
memcpy(trow->pData, ((STagRow *)row)->pData, trow->dataLen);
|
||||
return trow;
|
||||
}
|
||||
|
||||
SDataRow tdTagRowDecode(SDataRow row) {
|
||||
STagRow *trow = malloc(dataRowLen(row));
|
||||
if (trow == NULL) return NULL;
|
||||
|
||||
dataRowCpy(trow, row);
|
||||
trow->pData = malloc(trow->dataLen);
|
||||
if (NULL == trow->pData) {
|
||||
free(trow);
|
||||
return NULL;
|
||||
}
|
||||
char * pData = (char *)row + dataRowLen(row);
|
||||
memcpy(trow->pData, pData, trow->dataLen);
|
||||
return trow;
|
||||
}
|
||||
|
||||
int tdTagRowCpy(SDataRow dst, SDataRow src) {
|
||||
if (src == NULL) return -1;
|
||||
|
||||
dataRowCpy(dst, src);
|
||||
void * pData = dst + dataRowLen(src);
|
||||
memcpy(pData, ((STagRow *)src)->pData, ((STagRow *)src)->dataLen);
|
||||
return 0;
|
||||
}
|
||||
/**
|
||||
* Free the SDataRow object
|
||||
*/
|
||||
|
@ -330,7 +204,6 @@ void dataColInit(SDataCol *pDataCol, STColumn *pCol, void **pBuf, int maxPoints)
|
|||
pDataCol->pData = *pBuf;
|
||||
*pBuf = POINTER_SHIFT(*pBuf, pDataCol->spaceSize);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void dataColAppendVal(SDataCol *pCol, void *value, int numOfRows, int maxPoints) {
|
||||
|
@ -414,7 +287,7 @@ void dataColSetNEleNull(SDataCol *pCol, int nEle, int maxPoints) {
|
|||
void dataColSetOffset(SDataCol *pCol, int nEle) {
|
||||
ASSERT(((pCol->type == TSDB_DATA_TYPE_BINARY) || (pCol->type == TSDB_DATA_TYPE_NCHAR)));
|
||||
|
||||
void * tptr = pCol->pData;
|
||||
void *tptr = pCol->pData;
|
||||
// char *tptr = (char *)(pCol->pData);
|
||||
|
||||
VarDataOffsetT offset = 0;
|
||||
|
@ -594,4 +467,131 @@ void tdMergeTwoDataCols(SDataCols *target, SDataCols *src1, int *iter1, SDataCol
|
|||
(*iter2)++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SKVRow tdKVRowDup(SKVRow row) {
|
||||
SKVRow trow = malloc(kvRowLen(row));
|
||||
if (trow == NULL) return NULL;
|
||||
|
||||
kvRowCpy(trow, row);
|
||||
return trow;
|
||||
}
|
||||
|
||||
SKVRow tdSetKVRowDataOfCol(SKVRow row, int16_t colId, int8_t type, void *value) {
|
||||
// TODO
|
||||
return NULL;
|
||||
// SColIdx *pColIdx = NULL;
|
||||
// SKVRow rrow = row;
|
||||
// SKVRow nrow = NULL;
|
||||
// void *ptr = taosbsearch(&colId, kvDataRowColIdx(row), kvDataRowNCols(row), sizeof(SColIdx), comparTagId, TD_GE);
|
||||
|
||||
// if (ptr == NULL || ((SColIdx *)ptr)->colId < colId) { // need to add a column value to the row
|
||||
// int tlen = kvDataRowLen(row) + sizeof(SColIdx) + (IS_VAR_DATA_TYPE(type) ? varDataTLen(value) :
|
||||
// TYPE_BYTES[type]); nrow = malloc(tlen); if (nrow == NULL) return NULL;
|
||||
|
||||
// kvDataRowSetNCols(nrow, kvDataRowNCols(row)+1);
|
||||
// kvDataRowSetLen(nrow, tlen);
|
||||
|
||||
// if (ptr == NULL) ptr = kvDataRowValues(row);
|
||||
|
||||
// // Copy the columns before the col
|
||||
// if (POINTER_DISTANCE(ptr, kvDataRowColIdx(row)) > 0) {
|
||||
// memcpy(kvDataRowColIdx(nrow), kvDataRowColIdx(row), POINTER_DISTANCE(ptr, kvDataRowColIdx(row)));
|
||||
// memcpy(kvDataRowValues(nrow), kvDataRowValues(row), ((SColIdx *)ptr)->offset); // TODO: here is not correct
|
||||
// }
|
||||
|
||||
// // Set the new col value
|
||||
// pColIdx = (SColIdx *)POINTER_SHIFT(nrow, POINTER_DISTANCE(ptr, row));
|
||||
// pColIdx->colId = colId;
|
||||
// pColIdx->offset = ((SColIdx *)ptr)->offset; // TODO: here is not correct
|
||||
|
||||
// if (IS_VAR_DATA_TYPE(type)) {
|
||||
// memcpy(POINTER_SHIFT(kvDataRowValues(nrow), pColIdx->offset), value, varDataLen(value));
|
||||
// } else {
|
||||
// memcpy(POINTER_SHIFT(kvDataRowValues(nrow), pColIdx->offset), value, TYPE_BYTES[type]);
|
||||
// }
|
||||
|
||||
// // Copy the columns after the col
|
||||
// if (POINTER_DISTANCE(kvDataRowValues(row), ptr) > 0) {
|
||||
// // TODO: memcpy();
|
||||
// }
|
||||
// } else {
|
||||
// // TODO
|
||||
// ASSERT(((SColIdx *)ptr)->colId == colId);
|
||||
// if (IS_VAR_DATA_TYPE(type)) {
|
||||
// void *pOldVal = kvDataRowColVal(row, (SColIdx *)ptr);
|
||||
|
||||
// if (varDataTLen(value) == varDataTLen(pOldVal)) { // just update the column value in place
|
||||
// memcpy(pOldVal, value, varDataTLen(value));
|
||||
// } else { // enlarge the memory
|
||||
// // rrow = realloc(rrow, kvDataRowLen(rrow) + varDataTLen(value) - varDataTLen(pOldVal));
|
||||
// // if (rrow == NULL) return NULL;
|
||||
// // memmove();
|
||||
// // for () {
|
||||
// // ((SColIdx *)ptr)->offset += balabala;
|
||||
// // }
|
||||
|
||||
// // kvDataRowSetLen();
|
||||
|
||||
// }
|
||||
// } else {
|
||||
// memcpy(kvDataRowColVal(row, (SColIdx *)ptr), value, TYPE_BYTES[type]);
|
||||
// }
|
||||
// }
|
||||
|
||||
// return rrow;
|
||||
}
|
||||
|
||||
void *tdEncodeKVRow(void *buf, SKVRow row) {
|
||||
// May change the encode purpose
|
||||
kvRowCpy(buf, row);
|
||||
return POINTER_SHIFT(buf, kvRowLen(row));
|
||||
}
|
||||
|
||||
void *tdDecodeKVRow(void *buf, SKVRow *row) {
|
||||
*row = tdKVRowDup(buf);
|
||||
return POINTER_SHIFT(buf, kvRowLen(*row));
|
||||
}
|
||||
|
||||
int tdInitKVRowBuilder(SKVRowBuilder *pBuilder) {
|
||||
pBuilder->tCols = 128;
|
||||
pBuilder->nCols = 0;
|
||||
pBuilder->pColIdx = (SColIdx *)malloc(sizeof(SColIdx) * pBuilder->tCols);
|
||||
if (pBuilder->pColIdx == NULL) return -1;
|
||||
pBuilder->alloc = 1024;
|
||||
pBuilder->size = 0;
|
||||
pBuilder->buf = malloc(pBuilder->alloc);
|
||||
if (pBuilder->buf == NULL) {
|
||||
free(pBuilder->pColIdx);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void tdDestroyKVRowBuilder(SKVRowBuilder *pBuilder) {
|
||||
tfree(pBuilder->pColIdx);
|
||||
tfree(pBuilder->buf);
|
||||
}
|
||||
|
||||
void tdResetKVRowBuilder(SKVRowBuilder *pBuilder) {
|
||||
pBuilder->nCols = 0;
|
||||
pBuilder->size = 0;
|
||||
}
|
||||
|
||||
SKVRow tdGetKVRowFromBuilder(SKVRowBuilder *pBuilder) {
|
||||
int tlen = sizeof(SColIdx) * pBuilder->nCols + pBuilder->size;
|
||||
if (tlen == 0) return NULL;
|
||||
|
||||
tlen += TD_KV_ROW_HEAD_SIZE;
|
||||
|
||||
SKVRow row = malloc(tlen);
|
||||
if (row == NULL) return NULL;
|
||||
|
||||
kvRowSetNCols(row, pBuilder->nCols);
|
||||
kvRowSetLen(row, tlen);
|
||||
|
||||
memcpy(kvRowColIdx(row), pBuilder->pColIdx, sizeof(SColIdx) * pBuilder->nCols);
|
||||
memcpy(kvRowValues(row), pBuilder->buf, pBuilder->size);
|
||||
|
||||
return row;
|
||||
}
|
|
@ -55,11 +55,12 @@ int32_t tsEnableCoreFile = 0;
|
|||
int32_t tscEmbedded = 0;
|
||||
|
||||
/*
|
||||
* minmum scale for whole system, millisecond by default
|
||||
* minimum scale for whole system, millisecond by default
|
||||
* for TSDB_TIME_PRECISION_MILLI: 86400000L
|
||||
* TSDB_TIME_PRECISION_MICRO: 86400000000L
|
||||
* TSDB_TIME_PRECISION_NANO: 86400000000000L
|
||||
*/
|
||||
int64_t tsMsPerDay[] = {86400000L, 86400000000L};
|
||||
int64_t tsMsPerDay[] = {86400000L, 86400000000L, 86400000000000L};
|
||||
|
||||
char tsFirst[TSDB_EP_LEN] = {0};
|
||||
char tsSecond[TSDB_EP_LEN] = {0};
|
||||
|
@ -199,6 +200,8 @@ int32_t tsMonitorInterval = 30; // seconds
|
|||
char tsTimezone[64] = {0};
|
||||
char tsLocale[TSDB_LOCALE_LEN] = {0};
|
||||
char tsCharset[TSDB_LOCALE_LEN] = {0}; // default encode string
|
||||
char tsMqttBrokerAddress[128] = {0};
|
||||
char tsMqttBrokerClientId[128] = {0};
|
||||
|
||||
int32_t tsMaxBinaryDisplayWidth = 30;
|
||||
|
||||
|
@ -729,6 +732,26 @@ static void doInitGlobalConfig() {
|
|||
cfg.unitType = TAOS_CFG_UTYPE_NONE;
|
||||
taosInitConfigOption(cfg);
|
||||
|
||||
cfg.option = "mqttBrokerAddress";
|
||||
cfg.ptr = tsMqttBrokerAddress;
|
||||
cfg.valType = TAOS_CFG_VTYPE_STRING;
|
||||
cfg.cfgType = TSDB_CFG_CTYPE_B_CONFIG | TSDB_CFG_CTYPE_B_CLIENT | TSDB_CFG_CTYPE_B_NOT_PRINT;
|
||||
cfg.minValue = 0;
|
||||
cfg.maxValue = 0;
|
||||
cfg.ptrLength = 126;
|
||||
cfg.unitType = TAOS_CFG_UTYPE_NONE;
|
||||
taosInitConfigOption(cfg);
|
||||
|
||||
cfg.option = "mqttBrokerClientId";
|
||||
cfg.ptr = tsMqttBrokerClientId;
|
||||
cfg.valType = TAOS_CFG_VTYPE_STRING;
|
||||
cfg.cfgType = TSDB_CFG_CTYPE_B_CONFIG | TSDB_CFG_CTYPE_B_CLIENT | TSDB_CFG_CTYPE_B_NOT_PRINT;
|
||||
cfg.minValue = 0;
|
||||
cfg.maxValue = 0;
|
||||
cfg.ptrLength = 126;
|
||||
cfg.unitType = TAOS_CFG_UTYPE_NONE;
|
||||
taosInitConfigOption(cfg);
|
||||
|
||||
// socket type; udp by default
|
||||
cfg.option = "sockettype";
|
||||
cfg.ptr = tsSocketType;
|
||||
|
|
|
@ -32,6 +32,35 @@ const int32_t TYPE_BYTES[11] = {
|
|||
sizeof(VarDataOffsetT) // TSDB_DATA_TYPE_NCHAR
|
||||
};
|
||||
|
||||
static void getStatics_bool(const TSKEY *primaryKey, const void *pData, int32_t numOfRow, int64_t *min, int64_t *max,
|
||||
int64_t *sum, int16_t *minIndex, int16_t *maxIndex, int16_t *numOfNull) {
|
||||
int8_t *data = (int8_t *)pData;
|
||||
*min = INT64_MAX;
|
||||
*max = INT64_MIN;
|
||||
*minIndex = 0;
|
||||
*maxIndex = 0;
|
||||
|
||||
ASSERT(numOfRow <= INT16_MAX);
|
||||
|
||||
for (int32_t i = 0; i < numOfRow; ++i) {
|
||||
if (isNull((char *)&data[i], TSDB_DATA_TYPE_BOOL)) {
|
||||
(*numOfNull) += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
*sum += data[i];
|
||||
if (*min > data[i]) {
|
||||
*min = data[i];
|
||||
*minIndex = i;
|
||||
}
|
||||
|
||||
if (*max < data[i]) {
|
||||
*max = data[i];
|
||||
*maxIndex = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void getStatics_i8(const TSKEY *primaryKey, const void *pData, int32_t numOfRow, int64_t *min, int64_t *max,
|
||||
int64_t *sum, int16_t *minIndex, int16_t *maxIndex, int16_t *numOfNull) {
|
||||
int8_t *data = (int8_t *)pData;
|
||||
|
@ -131,15 +160,6 @@ static void getStatics_i32(const TSKEY *primaryKey, const void *pData, int32_t n
|
|||
*max = data[i];
|
||||
*maxIndex = i;
|
||||
}
|
||||
|
||||
// if (isNull(&lastVal, TSDB_DATA_TYPE_INT)) {
|
||||
// lastKey = primaryKey[i];
|
||||
// lastVal = data[i];
|
||||
// } else {
|
||||
// *wsum = lastVal * (primaryKey[i] - lastKey);
|
||||
// lastKey = primaryKey[i];
|
||||
// lastVal = data[i];
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -279,11 +299,11 @@ static void getStatics_bin(const TSKEY *primaryKey, const void *pData, int32_t n
|
|||
ASSERT(numOfRow <= INT16_MAX);
|
||||
|
||||
for (int32_t i = 0; i < numOfRow; ++i) {
|
||||
if (isNull((const char*) varDataVal(data), TSDB_DATA_TYPE_BINARY)) {
|
||||
if (isNull(data, TSDB_DATA_TYPE_BINARY)) {
|
||||
(*numOfNull) += 1;
|
||||
}
|
||||
|
||||
data += varDataLen(data);
|
||||
data += varDataTLen(data);
|
||||
}
|
||||
|
||||
*sum = 0;
|
||||
|
@ -299,11 +319,11 @@ static void getStatics_nchr(const TSKEY *primaryKey, const void *pData, int32_t
|
|||
ASSERT(numOfRow <= INT16_MAX);
|
||||
|
||||
for (int32_t i = 0; i < numOfRow; ++i) {
|
||||
if (isNull((const char*) varDataVal(data), TSDB_DATA_TYPE_NCHAR)) {
|
||||
if (isNull(data, TSDB_DATA_TYPE_NCHAR)) {
|
||||
(*numOfNull) += 1;
|
||||
}
|
||||
|
||||
data += varDataLen(data);
|
||||
data += varDataTLen(data);
|
||||
}
|
||||
|
||||
*sum = 0;
|
||||
|
@ -315,7 +335,7 @@ static void getStatics_nchr(const TSKEY *primaryKey, const void *pData, int32_t
|
|||
|
||||
tDataTypeDescriptor tDataTypeDesc[11] = {
|
||||
{TSDB_DATA_TYPE_NULL, 6, 1, "NOTYPE", NULL, NULL, NULL},
|
||||
{TSDB_DATA_TYPE_BOOL, 4, CHAR_BYTES, "BOOL", tsCompressBool, tsDecompressBool, getStatics_i8},
|
||||
{TSDB_DATA_TYPE_BOOL, 4, CHAR_BYTES, "BOOL", tsCompressBool, tsDecompressBool, getStatics_bool},
|
||||
{TSDB_DATA_TYPE_TINYINT, 7, CHAR_BYTES, "TINYINT", tsCompressTinyint, tsDecompressTinyint, getStatics_i8},
|
||||
{TSDB_DATA_TYPE_SMALLINT, 8, SHORT_BYTES, "SMALLINT", tsCompressSmallint, tsDecompressSmallint, getStatics_i16},
|
||||
{TSDB_DATA_TYPE_INT, 3, INT_BYTES, "INT", tsCompressInt, tsDecompressInt, getStatics_i32},
|
||||
|
|
|
@ -59,9 +59,15 @@ int main(int argc, char *argv[]) {
|
|||
exit(-1);
|
||||
}
|
||||
|
||||
STSchema *pSchema = tdNewSchema(2);
|
||||
tdSchemaAddCol(pSchema, TSDB_DATA_TYPE_TIMESTAMP, 0, 8);
|
||||
tdSchemaAddCol(pSchema, TSDB_DATA_TYPE_INT, 1, 4);
|
||||
STSchemaBuilder schemaBuilder = {0};
|
||||
|
||||
tdInitTSchemaBuilder(&schemaBuilder, 0);
|
||||
tdAddColToSchema(&schemaBuilder, TSDB_DATA_TYPE_TIMESTAMP, 0, 8);
|
||||
tdAddColToSchema(&schemaBuilder, TSDB_DATA_TYPE_INT, 1, 4);
|
||||
|
||||
STSchema *pSchema = tdGetSchemaFromBuilder(&schemaBuilder);
|
||||
|
||||
tdDestroyTSchemaBuilder(&schemaBuilder);
|
||||
|
||||
for (int sid =1; sid<10; ++sid) {
|
||||
cqCreate(pCq, sid, "select avg(speed) from demo.t1 sliding(1s) interval(5s)", pSchema);
|
||||
|
|
|
@ -22,7 +22,7 @@ extern "C" {
|
|||
|
||||
int32_t dnodeInitModules();
|
||||
void dnodeStartModules();
|
||||
void dnodeCleanUpModules();
|
||||
void dnodeCleanupModules();
|
||||
void dnodeProcessModuleStatus(uint32_t moduleStatus);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
@ -36,6 +36,46 @@ static void dnodeCleanupStorage();
|
|||
static void dnodeSetRunStatus(SDnodeRunStatus status);
|
||||
static void dnodeCheckDataDirOpenned(char *dir);
|
||||
static SDnodeRunStatus tsDnodeRunStatus = TSDB_DNODE_RUN_STATUS_STOPPED;
|
||||
static int32_t dnodeInitComponents();
|
||||
static void dnodeCleanupComponents(int32_t stepId);
|
||||
|
||||
typedef struct {
|
||||
const char *const name;
|
||||
int (*init)();
|
||||
void (*cleanup)();
|
||||
} SDnodeComponent;
|
||||
|
||||
static const SDnodeComponent SDnodeComponents[] = {
|
||||
{"storage", dnodeInitStorage, dnodeCleanupStorage},
|
||||
{"vread", dnodeInitVnodeRead, dnodeCleanupVnodeRead},
|
||||
{"vwrite", dnodeInitVnodeWrite, dnodeCleanupVnodeWrite},
|
||||
{"mread", dnodeInitMnodeRead, dnodeCleanupMnodeRead},
|
||||
{"mwrite", dnodeInitMnodeWrite, dnodeCleanupMnodeWrite},
|
||||
{"mpeer", dnodeInitMnodePeer, dnodeCleanupMnodePeer},
|
||||
{"client", dnodeInitClient, dnodeCleanupClient},
|
||||
{"server", dnodeInitServer, dnodeCleanupServer},
|
||||
{"mgmt", dnodeInitMgmt, dnodeCleanupMgmt},
|
||||
{"modules", dnodeInitModules, dnodeCleanupModules},
|
||||
{"shell", dnodeInitShell, dnodeCleanupShell}
|
||||
};
|
||||
|
||||
static void dnodeCleanupComponents(int32_t stepId) {
|
||||
for (int32_t i = stepId; i >= 0; i--) {
|
||||
SDnodeComponents[i].cleanup();
|
||||
}
|
||||
}
|
||||
|
||||
static int32_t dnodeInitComponents() {
|
||||
int32_t code = 0;
|
||||
for (int32_t i = 0; i < sizeof(SDnodeComponents) / sizeof(SDnodeComponents[0]); i++) {
|
||||
if (SDnodeComponents[i].init() != 0) {
|
||||
dnodeCleanupComponents(i);
|
||||
code = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
int32_t dnodeInitSystem() {
|
||||
dnodeSetRunStatus(TSDB_DNODE_RUN_STATUS_INITIALIZE);
|
||||
|
@ -67,17 +107,9 @@ int32_t dnodeInitSystem() {
|
|||
|
||||
dPrint("start to initialize TDengine on %s", tsLocalEp);
|
||||
|
||||
if (dnodeInitStorage() != 0) return -1;
|
||||
if (dnodeInitVnodeRead() != 0) return -1;
|
||||
if (dnodeInitVnodeWrite() != 0) return -1;
|
||||
if (dnodeInitMnodeRead() != 0) return -1;
|
||||
if (dnodeInitMnodeWrite() != 0) return -1;
|
||||
if (dnodeInitMnodePeer() != 0) return -1;
|
||||
if (dnodeInitClient() != 0) return -1;
|
||||
if (dnodeInitServer() != 0) return -1;
|
||||
if (dnodeInitMgmt() != 0) return -1;
|
||||
if (dnodeInitModules() != 0) return -1;
|
||||
if (dnodeInitShell() != 0) return -1;
|
||||
if (dnodeInitComponents() != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
dnodeStartModules();
|
||||
dnodeSetRunStatus(TSDB_DNODE_RUN_STATUS_RUNING);
|
||||
|
@ -90,17 +122,7 @@ int32_t dnodeInitSystem() {
|
|||
void dnodeCleanUpSystem() {
|
||||
if (dnodeGetRunStatus() != TSDB_DNODE_RUN_STATUS_STOPPED) {
|
||||
dnodeSetRunStatus(TSDB_DNODE_RUN_STATUS_STOPPED);
|
||||
dnodeCleanupShell();
|
||||
dnodeCleanUpModules();
|
||||
dnodeCleanupMgmt();
|
||||
dnodeCleanupServer();
|
||||
dnodeCleanupClient();
|
||||
dnodeCleanupMnodePeer();
|
||||
dnodeCleanupMnodeWrite();
|
||||
dnodeCleanupMnodeRead();
|
||||
dnodeCleanupVnodeWrite();
|
||||
dnodeCleanupVnodeRead();
|
||||
dnodeCleanupStorage();
|
||||
dnodeCleanupComponents(sizeof(SDnodeComponents) / sizeof(SDnodeComponents[0]) - 1);
|
||||
taos_cleanup();
|
||||
taosCloseLog();
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
#include "tglobal.h"
|
||||
#include "mnode.h"
|
||||
#include "http.h"
|
||||
#include "mqtt.h"
|
||||
#include "tmqtt.h"
|
||||
#include "monitor.h"
|
||||
#include "dnodeInt.h"
|
||||
#include "dnodeModule.h"
|
||||
|
@ -83,8 +83,8 @@ static void dnodeAllocModules() {
|
|||
}
|
||||
}
|
||||
|
||||
void dnodeCleanUpModules() {
|
||||
for (int32_t module = 1; module < TSDB_MOD_MAX; ++module) {
|
||||
void dnodeCleanupModules() {
|
||||
for (EModuleType module = 1; module < TSDB_MOD_MAX; ++module) {
|
||||
if (tsModule[module].enable && tsModule[module].stopFp) {
|
||||
(*tsModule[module].stopFp)();
|
||||
}
|
||||
|
|
|
@ -39,11 +39,11 @@ int32_t main(int32_t argc, char *argv[]) {
|
|||
exit(EXIT_FAILURE);
|
||||
}
|
||||
} else if (strcmp(argv[i], "-V") == 0) {
|
||||
#ifdef _SYNC
|
||||
#ifdef _SYNC
|
||||
char *versionStr = "enterprise";
|
||||
#else
|
||||
#else
|
||||
char *versionStr = "community";
|
||||
#endif
|
||||
#endif
|
||||
printf("%s version: %s compatible_version: %s\n", versionStr, version, compatible_version);
|
||||
printf("gitinfo: %s\n", gitinfo);
|
||||
printf("gitinfoI: %s\n", gitinfoOfInternal);
|
||||
|
@ -93,8 +93,6 @@ int32_t main(int32_t argc, char *argv[]) {
|
|||
if (dnodeInitSystem() < 0) {
|
||||
syslog(LOG_ERR, "Error initialize TDengine system");
|
||||
closelog();
|
||||
|
||||
dnodeCleanUpSystem();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ typedef struct {
|
|||
} SReadMsg;
|
||||
|
||||
typedef struct {
|
||||
pthread_t thread; // thread
|
||||
pthread_t thread; // thread
|
||||
int32_t workerId; // worker ID
|
||||
} SReadWorker;
|
||||
|
||||
|
@ -85,8 +85,8 @@ void dnodeCleanupVnodeRead() {
|
|||
}
|
||||
}
|
||||
|
||||
taosCloseQset(readQset);
|
||||
free(readPool.readWorker);
|
||||
taosCloseQset(readQset);
|
||||
|
||||
dPrint("dnode read is closed");
|
||||
}
|
||||
|
@ -95,7 +95,7 @@ void dnodeDispatchToVnodeReadQueue(SRpcMsg *pMsg) {
|
|||
int32_t queuedMsgNum = 0;
|
||||
int32_t leftLen = pMsg->contLen;
|
||||
char *pCont = (char *) pMsg->pCont;
|
||||
void *pVnode;
|
||||
void *pVnode;
|
||||
|
||||
while (leftLen > 0) {
|
||||
SMsgHead *pHead = (SMsgHead *) pCont;
|
||||
|
@ -166,7 +166,7 @@ void *dnodeAllocateVnodeRqueue(void *pVnode) {
|
|||
} while (readPool.num < readPool.min);
|
||||
}
|
||||
|
||||
dTrace("pVnode:%p, read queue:%p is allocated", pVnode, queue);
|
||||
dTrace("pVnode:%p, read queue:%p is allocated", pVnode, queue);
|
||||
|
||||
return queue;
|
||||
}
|
||||
|
@ -177,13 +177,13 @@ void dnodeFreeVnodeRqueue(void *rqueue) {
|
|||
// dynamically adjust the number of threads
|
||||
}
|
||||
|
||||
static void dnodeContinueExecuteQuery(void* pVnode, void* qhandle, SReadMsg *pMsg) {
|
||||
static void dnodeContinueExecuteQuery(void* pVnode, void* qhandle, SReadMsg *pMsg) {
|
||||
SReadMsg *pRead = (SReadMsg *)taosAllocateQitem(sizeof(SReadMsg));
|
||||
pRead->rpcMsg = pMsg->rpcMsg;
|
||||
pRead->pCont = qhandle;
|
||||
pRead->contLen = 0;
|
||||
pRead->rpcMsg.msgType = TSDB_MSG_TYPE_QUERY;
|
||||
|
||||
|
||||
taos_queue queue = vnodeGetRqueue(pVnode);
|
||||
taosWriteQitem(queue, TAOS_QTYPE_RPC, pRead);
|
||||
}
|
||||
|
|
|
@ -32,9 +32,9 @@
|
|||
typedef struct {
|
||||
taos_qall qall;
|
||||
taos_qset qset; // queue set
|
||||
pthread_t thread; // thread
|
||||
pthread_t thread; // thread
|
||||
int32_t workerId; // worker ID
|
||||
} SWriteWorker;
|
||||
} SWriteWorker;
|
||||
|
||||
typedef struct {
|
||||
SRspRet rspRet;
|
||||
|
@ -136,17 +136,24 @@ void *dnodeAllocateVnodeWqueue(void *pVnode) {
|
|||
|
||||
taosAddIntoQset(pWorker->qset, queue, pVnode);
|
||||
pWorker->qall = taosAllocateQall();
|
||||
wWorkerPool.nextId = (wWorkerPool.nextId + 1) % wWorkerPool.max;
|
||||
|
||||
if (pWorker->qall == NULL) {
|
||||
taosCloseQset(pWorker->qset);
|
||||
taosCloseQueue(queue);
|
||||
return NULL;
|
||||
}
|
||||
pthread_attr_t thAttr;
|
||||
pthread_attr_init(&thAttr);
|
||||
pthread_attr_setdetachstate(&thAttr, PTHREAD_CREATE_JOINABLE);
|
||||
|
||||
if (pthread_create(&pWorker->thread, &thAttr, dnodeProcessWriteQueue, pWorker) != 0) {
|
||||
dError("failed to create thread to process read queue, reason:%s", strerror(errno));
|
||||
taosFreeQall(pWorker->qall);
|
||||
taosCloseQset(pWorker->qset);
|
||||
taosCloseQueue(queue);
|
||||
queue = NULL;
|
||||
} else {
|
||||
dTrace("write worker:%d is launched", pWorker->workerId);
|
||||
wWorkerPool.nextId = (wWorkerPool.nextId + 1) % wWorkerPool.max;
|
||||
}
|
||||
|
||||
pthread_attr_destroy(&thAttr);
|
||||
|
@ -195,7 +202,7 @@ static void *dnodeProcessWriteQueue(void *param) {
|
|||
|
||||
while (1) {
|
||||
numOfMsgs = taosReadAllQitemsFromQset(pWorker->qset, pWorker->qall, &pVnode);
|
||||
if (numOfMsgs ==0) {
|
||||
if (numOfMsgs == 0) {
|
||||
dTrace("dnodeProcessWriteQueee: got no message from qset, exiting...");
|
||||
break;
|
||||
}
|
||||
|
@ -243,7 +250,7 @@ static void dnodeHandleIdleWorker(SWriteWorker *pWorker) {
|
|||
|
||||
if (num > 0) {
|
||||
usleep(30000);
|
||||
sched_yield();
|
||||
sched_yield();
|
||||
} else {
|
||||
taosFreeQall(pWorker->qall);
|
||||
taosCloseQset(pWorker->qset);
|
||||
|
|
|
@ -52,6 +52,7 @@ typedef struct tstr {
|
|||
#define varDataCopy(dst, v) memcpy((dst), (void*) (v), varDataTLen(v))
|
||||
#define varDataLenByData(v) (*(VarDataLenT *)(((char*)(v)) - VARSTR_HEADER_SIZE))
|
||||
#define varDataSetLen(v, _len) (((VarDataLenT *)(v))[0] = (VarDataLenT) (_len))
|
||||
#define IS_VAR_DATA_TYPE(t) (((t) == TSDB_DATA_TYPE_BINARY) || ((t) == TSDB_DATA_TYPE_NCHAR))
|
||||
|
||||
// this data type is internally used only in 'in' query to hold the values
|
||||
#define TSDB_DATA_TYPE_ARRAY (TSDB_DATA_TYPE_NCHAR + 1)
|
||||
|
@ -91,6 +92,7 @@ extern const int32_t TYPE_BYTES[11];
|
|||
|
||||
#define TSDB_TIME_PRECISION_MILLI 0
|
||||
#define TSDB_TIME_PRECISION_MICRO 1
|
||||
#define TSDB_TIME_PRECISION_NANO 2
|
||||
|
||||
#define TSDB_TIME_PRECISION_MILLI_STR "ms"
|
||||
#define TSDB_TIME_PRECISION_MICRO_STR "us"
|
||||
|
@ -285,17 +287,17 @@ void tsDataSwap(void *pLeft, void *pRight, int32_t type, int32_t size);
|
|||
#define TSDB_MAX_COMMIT_TIME 40960
|
||||
#define TSDB_DEFAULT_COMMIT_TIME 3600
|
||||
|
||||
#define TSDB_MIN_PRECISION TSDB_PRECISION_MILLI
|
||||
#define TSDB_MAX_PRECISION TSDB_PRECISION_NANO
|
||||
#define TSDB_DEFAULT_PRECISION TSDB_PRECISION_MILLI
|
||||
#define TSDB_MIN_PRECISION TSDB_TIME_PRECISION_MILLI
|
||||
#define TSDB_MAX_PRECISION TSDB_TIME_PRECISION_NANO
|
||||
#define TSDB_DEFAULT_PRECISION TSDB_TIME_PRECISION_MILLI
|
||||
|
||||
#define TSDB_MIN_COMP_LEVEL 0
|
||||
#define TSDB_MAX_COMP_LEVEL 2
|
||||
#define TSDB_DEFAULT_COMP_LEVEL 2
|
||||
|
||||
#define TSDB_MIN_WAL_LEVEL 0
|
||||
#define TSDB_MAX_WAL_LEVEL 2
|
||||
#define TSDB_DEFAULT_WAL_LEVEL 2
|
||||
#define TSDB_MIN_WAL_LEVEL 1
|
||||
#define TSDB_MAX_WAL_LEVEL 2
|
||||
#define TSDB_DEFAULT_WAL_LEVEL 1
|
||||
|
||||
#define TSDB_MIN_REPLICA_NUM 1
|
||||
#define TSDB_MAX_REPLICA_NUM 3
|
||||
|
@ -356,12 +358,6 @@ void tsDataSwap(void *pLeft, void *pRight, int32_t type, int32_t size);
|
|||
#define TAOS_QTYPE_WAL 2
|
||||
#define TAOS_QTYPE_CQ 3
|
||||
|
||||
typedef enum {
|
||||
TSDB_PRECISION_MILLI,
|
||||
TSDB_PRECISION_MICRO,
|
||||
TSDB_PRECISION_NANO
|
||||
} EPrecisionType;
|
||||
|
||||
typedef enum {
|
||||
TSDB_SUPER_TABLE = 0, // super table
|
||||
TSDB_CHILD_TABLE = 1, // table created from super table
|
||||
|
|
|
@ -370,7 +370,7 @@ typedef struct SExprInfo {
|
|||
struct tExprNode* pExpr;
|
||||
int16_t bytes;
|
||||
int16_t type;
|
||||
int16_t interBytes;
|
||||
int32_t interBytes;
|
||||
} SExprInfo;
|
||||
|
||||
typedef struct SColumnFilterInfo {
|
||||
|
@ -620,13 +620,6 @@ typedef struct {
|
|||
SCMVgroupInfo vgroups[];
|
||||
} SVgroupsInfo;
|
||||
|
||||
//typedef struct {
|
||||
// int32_t numOfTables;
|
||||
// int32_t join;
|
||||
// int32_t joinCondLen; // for join condition
|
||||
// int32_t metaElem[TSDB_MAX_JOIN_TABLE_NUM];
|
||||
//} SSuperTableMetaMsg;
|
||||
|
||||
typedef struct STableMetaMsg {
|
||||
int32_t contLen;
|
||||
char tableId[TSDB_TABLE_ID_LEN + 1]; // table id
|
||||
|
|
|
@ -19,10 +19,7 @@
|
|||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
int32_t mqttGetReqCount();
|
||||
int32_t mqttInitSystem();
|
||||
int32_t mqttStartSystem();
|
||||
void mqttStopSystem();
|
|
@ -64,13 +64,14 @@ typedef struct {
|
|||
int8_t compression;
|
||||
} STsdbCfg;
|
||||
|
||||
typedef void TsdbRepoT; // use void to hide implementation details from outside
|
||||
|
||||
void tsdbSetDefaultCfg(STsdbCfg *pCfg);
|
||||
STsdbCfg *tsdbCreateDefaultCfg();
|
||||
void tsdbFreeCfg(STsdbCfg *pCfg);
|
||||
STsdbCfg *tsdbGetCfg(const TsdbRepoT *repo);
|
||||
|
||||
// --------- TSDB REPOSITORY DEFINITION
|
||||
typedef void TsdbRepoT; // use void to hide implementation details from outside
|
||||
|
||||
int tsdbCreateRepo(char *rootDir, STsdbCfg *pCfg, void *limiter);
|
||||
int32_t tsdbDropRepo(TsdbRepoT *repo);
|
||||
TsdbRepoT *tsdbOpenRepo(char *rootDir, STsdbAppH *pAppH);
|
||||
|
@ -101,14 +102,15 @@ int tsdbInitTableCfg(STableCfg *config, ETableType type, uint64_t uid, int32_t
|
|||
int tsdbTableSetSuperUid(STableCfg *config, uint64_t uid);
|
||||
int tsdbTableSetSchema(STableCfg *config, STSchema *pSchema, bool dup);
|
||||
int tsdbTableSetTagSchema(STableCfg *config, STSchema *pSchema, bool dup);
|
||||
int tsdbTableSetTagValue(STableCfg *config, SDataRow row, bool dup);
|
||||
int tsdbTableSetTagValue(STableCfg *config, SKVRow row, bool dup);
|
||||
int tsdbTableSetName(STableCfg *config, char *name, bool dup);
|
||||
int tsdbTableSetSName(STableCfg *config, char *sname, bool dup);
|
||||
int tsdbTableSetStreamSql(STableCfg *config, char *sql, bool dup);
|
||||
void tsdbClearTableCfg(STableCfg *config);
|
||||
|
||||
int32_t tsdbGetTableTagVal(TsdbRepoT *repo, STableId* id, int32_t colId, int16_t *type, int16_t *bytes, char **val);
|
||||
char* tsdbGetTableName(TsdbRepoT *repo, const STableId* id, int16_t* bytes);
|
||||
int32_t tsdbGetTableTagVal(TsdbRepoT *repo, STableId *id, int32_t colId, int16_t *type, int16_t *bytes, char **val);
|
||||
char * tsdbGetTableName(TsdbRepoT *repo, const STableId *id, int16_t *bytes);
|
||||
STableCfg *tsdbCreateTableCfgFromMsg(SMDCreateTableMsg *pMsg);
|
||||
|
||||
int tsdbCreateTable(TsdbRepoT *repo, STableCfg *pCfg);
|
||||
int tsdbDropTable(TsdbRepoT *pRepo, STableId tableId);
|
||||
|
@ -200,6 +202,10 @@ TsdbQueryHandleT *tsdbQueryTables(TsdbRepoT *tsdb, STsdbQueryCond *pCond, STable
|
|||
*/
|
||||
TsdbQueryHandleT tsdbQueryLastRow(TsdbRepoT *tsdb, STsdbQueryCond *pCond, STableGroupInfo *groupInfo);
|
||||
|
||||
SArray* tsdbGetQueriedTableIdList(TsdbQueryHandleT *pHandle);
|
||||
|
||||
TsdbQueryHandleT tsdbQueryRowsInExternalWindow(TsdbRepoT *tsdb, STsdbQueryCond* pCond, STableGroupInfo *groupList);
|
||||
|
||||
/**
|
||||
* move to next block if exists
|
||||
*
|
||||
|
|
|
@ -276,8 +276,8 @@ static int32_t mnodeCheckDbCfg(SDbCfg *pCfg) {
|
|||
return TSDB_CODE_INVALID_OPTION;
|
||||
}
|
||||
|
||||
if (pCfg->replications > 1 && pCfg->walLevel <= TSDB_MIN_WAL_LEVEL) {
|
||||
mError("invalid db option walLevel:%d must > 0, while replica:%d > 1", pCfg->walLevel, pCfg->replications);
|
||||
if (pCfg->walLevel < TSDB_MIN_WAL_LEVEL) {
|
||||
mError("invalid db option walLevel:%d must be greater than 0", pCfg->walLevel);
|
||||
return TSDB_CODE_INVALID_OPTION;
|
||||
}
|
||||
|
||||
|
@ -871,8 +871,8 @@ static SDbCfg mnodeGetAlterDbOption(SDbObj *pDb, SCMAlterDbMsg *pAlter) {
|
|||
mTrace("db:%s, replications:%d change to %d", pDb->name, pDb->cfg.replications, replications);
|
||||
newCfg.replications = replications;
|
||||
|
||||
if (replications > 1 && pDb->cfg.walLevel <= TSDB_MIN_WAL_LEVEL) {
|
||||
mError("db:%s, walLevel:%d must > 0, while replica:%d > 1", pDb->name, pDb->cfg.walLevel, replications);
|
||||
if (pDb->cfg.walLevel < TSDB_MIN_WAL_LEVEL) {
|
||||
mError("db:%s, walLevel:%d must be greater than 0", pDb->name, pDb->cfg.walLevel);
|
||||
terrno = TSDB_CODE_INVALID_OPTION;
|
||||
}
|
||||
|
||||
|
|
|
@ -280,6 +280,12 @@ static int32_t mnodeGetUserMeta(STableMetaMsg *pMeta, SShowObj *pShow, void *pCo
|
|||
pSchema[cols].bytes = htons(pShow->bytes[cols]);
|
||||
cols++;
|
||||
|
||||
pShow->bytes[cols] = TSDB_USER_LEN + VARSTR_HEADER_SIZE;
|
||||
pSchema[cols].type = TSDB_DATA_TYPE_BINARY;
|
||||
strcpy(pSchema[cols].name, "account");
|
||||
pSchema[cols].bytes = htons(pShow->bytes[cols]);
|
||||
cols++;
|
||||
|
||||
pMeta->numOfColumns = htons(cols);
|
||||
strcpy(pMeta->tableId, "show users");
|
||||
pShow->numOfColumns = cols;
|
||||
|
@ -329,6 +335,10 @@ static int32_t mnodeRetrieveUsers(SShowObj *pShow, char *data, int32_t rows, voi
|
|||
*(int64_t *)pWrite = pUser->createdTime;
|
||||
cols++;
|
||||
|
||||
pWrite = data + pShow->offset[cols] * rows + pShow->bytes[cols] * numOfRows;
|
||||
STR_WITH_MAXSIZE_TO_VARSTR(pWrite, pUser->acct, TSDB_USER_LEN);
|
||||
cols++;
|
||||
|
||||
numOfRows++;
|
||||
mnodeDecUserRef(pUser);
|
||||
}
|
||||
|
|
|
@ -7,16 +7,16 @@ IF ((TD_LINUX_64) OR (TD_LINUX_32 AND TD_ARM))
|
|||
INCLUDE_DIRECTORIES(${TD_COMMUNITY_DIR}/src/util/inc)
|
||||
INCLUDE_DIRECTORIES(${TD_COMMUNITY_DIR}/src/query/inc)
|
||||
INCLUDE_DIRECTORIES(${TD_COMMUNITY_DIR}/src/common/inc)
|
||||
INCLUDE_DIRECTORIES(${TD_COMMUNITY_DIR}/deps/zlib-1.2.11/inc)
|
||||
INCLUDE_DIRECTORIES(${TD_COMMUNITY_DIR}/deps/cJson/inc)
|
||||
INCLUDE_DIRECTORIES(${TD_COMMUNITY_DIR}/deps/lz4/inc)
|
||||
INCLUDE_DIRECTORIES(${TD_COMMUNITY_DIR}/deps/MQTT-C/include)
|
||||
INCLUDE_DIRECTORIES(${TD_COMMUNITY_DIR}/deps/MQTT-C/examples/templates)
|
||||
INCLUDE_DIRECTORIES(${TD_OS_DIR}/inc)
|
||||
INCLUDE_DIRECTORIES(inc)
|
||||
AUX_SOURCE_DIRECTORY(src SRC)
|
||||
ADD_LIBRARY(mqtt ${SRC})
|
||||
TARGET_LINK_LIBRARIES(mqtt taos_static z)
|
||||
TARGET_LINK_LIBRARIES(mqtt taos_static cJson mqttc)
|
||||
|
||||
IF (TD_ADMIN)
|
||||
TARGET_LINK_LIBRARIES(mqtt admin)
|
||||
TARGET_LINK_LIBRARIES(mqtt admin cJson)
|
||||
ENDIF ()
|
||||
ENDIF ()
|
||||
|
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||
*
|
||||
* This program is free software: you can use, redistribute, and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3
|
||||
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef TDENGINE_MQTT_INIT_H
|
||||
#define TDENGINE_MQTT_INIT_H
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @file
|
||||
* A simple subscriber program that performs automatic reconnections.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include "mqtt.h"
|
||||
#include "taos.h"
|
||||
|
||||
/**
|
||||
* @brief A structure that I will use to keep track of some data needed
|
||||
* to setup the connection to the broker.
|
||||
*
|
||||
* An instance of this struct will be created in my \c main(). Then, whenever
|
||||
* \ref mqttReconnectClient is called, this instance will be passed.
|
||||
*/
|
||||
struct reconnect_state_t {
|
||||
char* hostname;
|
||||
char* port;
|
||||
char* topic;
|
||||
char* client_id;
|
||||
char* user_name;
|
||||
char* password;
|
||||
uint8_t* sendbuf;
|
||||
size_t sendbufsz;
|
||||
uint8_t* recvbuf;
|
||||
size_t recvbufsz;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief My reconnect callback. It will reestablish the connection whenever
|
||||
* an error occurs.
|
||||
*/
|
||||
void mqttReconnectClient(struct mqtt_client* client, void** reconnect_state_vptr);
|
||||
|
||||
/**
|
||||
* @brief The function will be called whenever a PUBLISH message is received.
|
||||
*/
|
||||
void mqtt_PublishCallback(void** unused, struct mqtt_response_publish* published);
|
||||
|
||||
/**
|
||||
* @brief The client's refresher. This function triggers back-end routines to
|
||||
* handle ingress/egress traffic to the broker.
|
||||
*
|
||||
* @note All this function needs to do is call \ref __mqtt_recv and
|
||||
* \ref __mqtt_send every so often. I've picked 100 ms meaning that
|
||||
* client ingress/egress traffic will be handled every 100 ms.
|
||||
*/
|
||||
void* mqttClientRefresher(void* client);
|
||||
|
||||
/**
|
||||
* @brief Safelty closes the \p sockfd and cancels the \p client_daemon before \c exit.
|
||||
*/
|
||||
|
||||
void mqttCleanup(int status, int sockfd, pthread_t* client_daemon);
|
||||
void mqttInitConnCb(void* param, TAOS_RES* result, int32_t code);
|
||||
void mqttQueryInsertCallback(void* param, TAOS_RES* result, int32_t code);
|
||||
#define QOS 1
|
||||
#define TIMEOUT 10000L
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||
*
|
||||
* This program is free software: you can use, redistribute, and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3
|
||||
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef TDENGINE_MQTT_PLYLOAD_H
|
||||
#define TDENGINE_MQTT_PLYLOAD_H
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
char split(char str[], char delims[], char** p_p_cmd_part, int max);
|
||||
char* converJsonToSql(char* json, char* _dbname, char* _tablename);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -18,15 +18,11 @@
|
|||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
int32_t mqttGetReqCount();
|
||||
int32_t mqttInitSystem();
|
||||
int32_t mqttStartSystem();
|
||||
void mqttStopSystem();
|
||||
void mqttCleanUpSystem();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||
*
|
||||
* This program is free software: you can use, redistribute, and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3
|
||||
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define _DEFAULT_SOURCE
|
||||
#include "mqttPayload.h"
|
||||
#include "cJSON.h"
|
||||
#include "string.h"
|
||||
#include "taos.h"
|
||||
#include "mqttLog.h"
|
||||
#include "os.h"
|
||||
char split(char str[], char delims[], char** p_p_cmd_part, int max) {
|
||||
char* token = strtok(str, delims);
|
||||
char part_index = 0;
|
||||
char** tmp_part = p_p_cmd_part;
|
||||
while (token) {
|
||||
*tmp_part++ = token;
|
||||
token = strtok(NULL, delims);
|
||||
part_index++;
|
||||
if (part_index >= max) break;
|
||||
}
|
||||
return part_index;
|
||||
}
|
||||
|
||||
char* converJsonToSql(char* json, char* _dbname, char* _tablename) {
|
||||
cJSON* jPlayload = cJSON_Parse(json);
|
||||
char _names[102400] = {0};
|
||||
char _values[102400] = {0};
|
||||
int i = 0;
|
||||
int count = cJSON_GetArraySize(jPlayload);
|
||||
for (; i < count; i++)
|
||||
{
|
||||
cJSON* item = cJSON_GetArrayItem(jPlayload, i);
|
||||
if (cJSON_Object == item->type) {
|
||||
mqttPrint("The item '%s' is not supported", item->string);
|
||||
} else {
|
||||
strcat(_names, item->string);
|
||||
if (i < count - 1) {
|
||||
strcat(_names, ",");
|
||||
}
|
||||
char* __value_json = cJSON_Print(item);
|
||||
strcat(_values, __value_json);
|
||||
free(__value_json);
|
||||
if (i < count - 1) {
|
||||
strcat(_values, ",");
|
||||
}
|
||||
}
|
||||
}
|
||||
cJSON_free(jPlayload);
|
||||
int sqllen = strlen(_names) + strlen(_values) + strlen(_dbname) + strlen(_tablename) + 1024;
|
||||
char* _sql = calloc(1, sqllen);
|
||||
sprintf(_sql, "INSERT INTO %s.%s (%s) VALUES(%s);", _dbname, _tablename, _names, _values);
|
||||
return _sql;
|
||||
}
|
|
@ -14,30 +14,218 @@
|
|||
*/
|
||||
|
||||
#define _DEFAULT_SOURCE
|
||||
#include "mqttSystem.h"
|
||||
|
||||
#include "cJSON.h"
|
||||
#include "mqtt.h"
|
||||
#include "mqttInit.h"
|
||||
#include "mqttLog.h"
|
||||
#include "mqttPayload.h"
|
||||
#include "os.h"
|
||||
#include "posix_sockets.h"
|
||||
#include "string.h"
|
||||
#include "taos.h"
|
||||
#include "tglobal.h"
|
||||
#include "tmqtt.h"
|
||||
#include "tsclient.h"
|
||||
#include "tsocket.h"
|
||||
#include "ttimer.h"
|
||||
#include "mqttSystem.h"
|
||||
struct mqtt_client mqttClient = {0};
|
||||
pthread_t clientDaemonThread = {0};
|
||||
void* mqttConnect=NULL;
|
||||
struct reconnect_state_t recntStatus = {0};
|
||||
char* topicPath=NULL;
|
||||
int mttIsRuning = 1;
|
||||
|
||||
int32_t mqttGetReqCount() { return 0; }
|
||||
int mqttInitSystem() {
|
||||
mqttPrint("mqttInitSystem");
|
||||
return 0;
|
||||
int32_t mqttInitSystem() {
|
||||
int rc = 0;
|
||||
uint8_t sendbuf[2048];
|
||||
uint8_t recvbuf[1024];
|
||||
recntStatus.sendbuf = sendbuf;
|
||||
recntStatus.sendbufsz = sizeof(sendbuf);
|
||||
recntStatus.recvbuf = recvbuf;
|
||||
recntStatus.recvbufsz = sizeof(recvbuf);
|
||||
char* url = tsMqttBrokerAddress;
|
||||
recntStatus.user_name = strstr(url, "@") != NULL ? strbetween(url, "//", ":") : NULL;
|
||||
recntStatus.password = strstr(url, "@") != NULL ? strbetween(strstr(url, recntStatus.user_name), ":", "@") : NULL;
|
||||
|
||||
if (strlen(url) == 0) {
|
||||
mqttTrace("mqtt module not init, url is null");
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (strstr(url, "@") != NULL) {
|
||||
recntStatus.hostname = strbetween(url, "@", ":");
|
||||
} else if (strstr(strstr(url, "://") + 3, ":") != NULL) {
|
||||
recntStatus.hostname = strbetween(url, "//", ":");
|
||||
|
||||
} else {
|
||||
recntStatus.hostname = strbetween(url, "//", "/");
|
||||
}
|
||||
|
||||
char* _begin_hostname = strstr(url, recntStatus.hostname);
|
||||
if (strstr(_begin_hostname, ":") != NULL) {
|
||||
recntStatus.port = strbetween(_begin_hostname, ":", "/");
|
||||
} else {
|
||||
recntStatus.port = strbetween("'1883'", "'", "'");
|
||||
}
|
||||
|
||||
topicPath = strbetween(strstr(url, strstr(_begin_hostname, ":") != NULL ? recntStatus.port : recntStatus.hostname),
|
||||
"/", "/");
|
||||
char* _topic = "+/+/+/";
|
||||
int _tpsize = strlen(topicPath) + strlen(_topic) + 1;
|
||||
recntStatus.topic = calloc(1, _tpsize);
|
||||
sprintf(recntStatus.topic, "/%s/%s", topicPath, _topic);
|
||||
recntStatus.client_id = strlen(tsMqttBrokerClientId) < 3 ? tsMqttBrokerClientId : "taos_mqtt";
|
||||
mqttConnect = NULL;
|
||||
return rc;
|
||||
}
|
||||
|
||||
int mqttStartSystem() {
|
||||
mqttPrint("mqttStartSystem");
|
||||
return 0;
|
||||
int32_t mqttStartSystem() {
|
||||
int rc = 0;
|
||||
if (recntStatus.user_name != NULL && recntStatus.password != NULL) {
|
||||
mqttPrint("connecting to mqtt://%s:%s@%s:%s/%s/", recntStatus.user_name, recntStatus.password,
|
||||
recntStatus.hostname, recntStatus.port, topicPath);
|
||||
} else if (recntStatus.user_name != NULL && recntStatus.password == NULL) {
|
||||
mqttPrint("connecting to mqtt://%s@%s:%s/%s/", recntStatus.user_name, recntStatus.hostname, recntStatus.port,
|
||||
topicPath);
|
||||
}
|
||||
|
||||
mqtt_init_reconnect(&mqttClient, mqttReconnectClient, &recntStatus, mqtt_PublishCallback);
|
||||
if (pthread_create(&clientDaemonThread, NULL, mqttClientRefresher, &mqttClient)) {
|
||||
mqttError("Failed to start client daemon.");
|
||||
mqttCleanup(EXIT_FAILURE, -1, NULL);
|
||||
rc = -1;
|
||||
} else {
|
||||
mqttPrint("listening for '%s' messages.", recntStatus.topic);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
void mqttStopSystem() {
|
||||
mqttPrint("mqttStopSystem");
|
||||
mqttClient.error = MQTT_ERROR_SOCKET_ERROR;
|
||||
mttIsRuning = 0;
|
||||
usleep(300000U);
|
||||
mqttCleanup(EXIT_SUCCESS, mqttClient.socketfd, &clientDaemonThread);
|
||||
mqttPrint("mqtt is stoped");
|
||||
}
|
||||
|
||||
void mqttCleanUpSystem() {
|
||||
mqttPrint("mqttCleanUpSystem");
|
||||
void mqttCleanUpSystem() {
|
||||
mqttPrint("starting to clean up mqtt");
|
||||
free(recntStatus.user_name);
|
||||
free(recntStatus.password);
|
||||
free(recntStatus.hostname);
|
||||
free(recntStatus.port);
|
||||
free(recntStatus.topic);
|
||||
free(topicPath);
|
||||
mqttPrint("mqtt is cleaned up");
|
||||
}
|
||||
|
||||
void mqtt_PublishCallback(void** unused, struct mqtt_response_publish* published) {
|
||||
mqttPrint("mqtt_PublishCallback");
|
||||
/* note that published->topic_name is NOT null-terminated (here we'll change it to a c-string) */
|
||||
char* topic_name = (char*)malloc(published->topic_name_size + 1);
|
||||
memcpy(topic_name, published->topic_name, published->topic_name_size);
|
||||
topic_name[published->topic_name_size] = '\0';
|
||||
mqttPrint("Received publish('%s'): %s", topic_name, (const char*)published->application_message);
|
||||
char _token[128] = {0};
|
||||
char _dbname[128] = {0};
|
||||
char _tablename[128] = {0};
|
||||
if (mqttConnect == NULL) {
|
||||
mqttPrint("connect database");
|
||||
taos_connect_a(NULL, "_root", tsInternalPass, "", 0, mqttInitConnCb, &mqttClient, &mqttConnect);
|
||||
}
|
||||
if (topic_name[1]=='/' && strncmp((char*)&topic_name[1], topicPath, strlen(topicPath)) == 0) {
|
||||
char* p_p_cmd_part[5] = {0};
|
||||
char copystr[1024] = {0};
|
||||
strncpy(copystr, topic_name, MIN(1024, published->topic_name_size));
|
||||
char part_index = split(copystr, "/", p_p_cmd_part, 10);
|
||||
if (part_index < 4) {
|
||||
mqttError("The topic %s is't format '/path/token/dbname/table name/'. for expmle: '/taos/token/db/t'", topic_name);
|
||||
} else {
|
||||
strncpy(_token, p_p_cmd_part[1], 127);
|
||||
strncpy(_dbname, p_p_cmd_part[2], 127);
|
||||
strncpy(_tablename, p_p_cmd_part[3], 127);
|
||||
mqttPrint("part count=%d,access token:%s,database name:%s, table name:%s", part_index, _token, _dbname,
|
||||
_tablename);
|
||||
|
||||
if (mqttConnect != NULL) {
|
||||
char* _sql = converJsonToSql((char*)published->application_message, _dbname, _tablename);
|
||||
mqttPrint("query:%s", _sql);
|
||||
taos_query_a(mqttConnect, _sql, mqttQueryInsertCallback, &mqttClient);
|
||||
mqttPrint("free sql:%s", _sql);
|
||||
free(_sql);
|
||||
}
|
||||
}
|
||||
}
|
||||
free(topic_name);
|
||||
}
|
||||
|
||||
void* mqttClientRefresher(void* client) {
|
||||
while (mttIsRuning) {
|
||||
mqtt_sync((struct mqtt_client*)client);
|
||||
usleep(100000U);
|
||||
}
|
||||
mqttPrint("Exit mqttClientRefresher");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void mqttCleanup(int status, int sockfd, pthread_t* client_daemon) {
|
||||
mqttPrint("mqttCleanup");
|
||||
if (sockfd != -1) close(sockfd);
|
||||
if (client_daemon != NULL) pthread_cancel(*client_daemon);
|
||||
}
|
||||
|
||||
void mqttInitConnCb(void* param, TAOS_RES* result, int32_t code) {
|
||||
if (code < 0) {
|
||||
mqttError("mqtt:%d, connect to database failed, reason:%s", code, tstrerror(code));
|
||||
taos_close(mqttConnect);
|
||||
mqttConnect = NULL;
|
||||
return;
|
||||
}
|
||||
mqttTrace("mqtt:%d, connect to database success, reason:%s", code, tstrerror(code));
|
||||
}
|
||||
|
||||
void mqttQueryInsertCallback(void* param, TAOS_RES* result, int32_t code) {
|
||||
if (code < 0) {
|
||||
mqttError("mqtt:%d, save data failed, code:%s", code, tstrerror(code));
|
||||
} else if (code == 0) {
|
||||
mqttError("mqtt:%d, save data failed, affect rows:%d", code, code);
|
||||
} else {
|
||||
mqttPrint("mqtt:%d, save data success, code:%s", code, tstrerror(code));
|
||||
}
|
||||
}
|
||||
|
||||
void mqttReconnectClient(struct mqtt_client* client, void** reconnect_state_vptr) {
|
||||
mqttPrint("mqttReconnectClient");
|
||||
struct reconnect_state_t* reconnect_state = *((struct reconnect_state_t**)reconnect_state_vptr);
|
||||
|
||||
/* Close the clients socket if this isn't the initial reconnect call */
|
||||
if (client->error != MQTT_ERROR_INITIAL_RECONNECT) {
|
||||
close(client->socketfd);
|
||||
}
|
||||
|
||||
/* Perform error handling here. */
|
||||
if (client->error != MQTT_ERROR_INITIAL_RECONNECT) {
|
||||
mqttError("mqttReconnectClient: called while client was in error state \"%s\"", mqtt_error_str(client->error));
|
||||
}
|
||||
|
||||
/* Open a new socket. */
|
||||
int sockfd = open_nb_socket(reconnect_state->hostname, reconnect_state->port);
|
||||
if (sockfd == -1) {
|
||||
mqttError("Failed to open socket: ");
|
||||
mqttCleanup(EXIT_FAILURE, sockfd, NULL);
|
||||
}
|
||||
|
||||
/* Reinitialize the client. */
|
||||
mqtt_reinit(client, sockfd, reconnect_state->sendbuf, reconnect_state->sendbufsz, reconnect_state->recvbuf,
|
||||
reconnect_state->recvbufsz);
|
||||
|
||||
/* Ensure we have a clean session */
|
||||
uint8_t connect_flags = MQTT_CONNECT_CLEAN_SESSION;
|
||||
/* Send connection request to the broker. */
|
||||
mqtt_connect(client, reconnect_state->client_id, NULL, NULL, 0, reconnect_state->user_name, reconnect_state->password,connect_flags, 400);
|
||||
|
||||
/* Subscribe to the topic. */
|
||||
mqtt_subscribe(client, reconnect_state->topic, 0);
|
||||
}
|
|
@ -28,21 +28,16 @@
|
|||
#include "tsdb.h"
|
||||
#include "tsqlfunction.h"
|
||||
|
||||
//typedef struct tFilePage {
|
||||
// int64_t num;
|
||||
// char data[];
|
||||
//} tFilePage;
|
||||
|
||||
struct SColumnFilterElem;
|
||||
typedef bool (*__filter_func_t)(struct SColumnFilterElem* pFilter, char* val1, char* val2);
|
||||
typedef int32_t (*__block_search_fn_t)(char* data, int32_t num, int64_t key, int32_t order);
|
||||
|
||||
typedef struct SSqlGroupbyExpr {
|
||||
int16_t tableIndex;
|
||||
SArray* columnInfo; // SArray<SColIndex>, group by columns information
|
||||
int16_t numOfGroupCols;
|
||||
int16_t orderIndex; // order by column index
|
||||
int16_t orderType; // order by type: asc/desc
|
||||
int16_t tableIndex;
|
||||
SArray* columnInfo; // SArray<SColIndex>, group by columns information
|
||||
int16_t numOfGroupCols;
|
||||
int16_t orderIndex; // order by column index
|
||||
int16_t orderType; // order by type: asc/desc
|
||||
} SSqlGroupbyExpr;
|
||||
|
||||
typedef struct SPosInfo {
|
||||
|
@ -62,25 +57,27 @@ typedef struct SWindowResult {
|
|||
SWindowStatus status; // this result status: closed or opened
|
||||
} SWindowResult;
|
||||
|
||||
/**
|
||||
* If the number of generated results is greater than this value,
|
||||
* query query will be halt and return results to client immediate.
|
||||
*/
|
||||
typedef struct SResultRec {
|
||||
int64_t total; // total generated result size in rows
|
||||
int64_t rows; // current result set size in rows
|
||||
int64_t capacity; // capacity of current result output buffer
|
||||
|
||||
// result size threshold in rows. If the result buffer is larger than this, pause query and return to client
|
||||
int32_t threshold;
|
||||
int64_t total; // total generated result size in rows
|
||||
int64_t rows; // current result set size in rows
|
||||
int64_t capacity; // capacity of current result output buffer
|
||||
int32_t threshold; // result size threshold in rows.
|
||||
} SResultRec;
|
||||
|
||||
typedef struct SWindowResInfo {
|
||||
SWindowResult* pResult; // result list
|
||||
void* hashList; // hash list for quick access
|
||||
SHashObj* hashList; // hash list for quick access
|
||||
int16_t type; // data type for hash key
|
||||
int32_t capacity; // max capacity
|
||||
int32_t curIndex; // current start active index
|
||||
int32_t size; // number of result set
|
||||
int64_t startTime; // start time of the first time window for sliding query
|
||||
int64_t prevSKey; // previous (not completed) sliding window start key
|
||||
int64_t threshold; // threshold to pausing query and return closed results.
|
||||
int64_t threshold; // threshold to halt query and return the generated results.
|
||||
} SWindowResInfo;
|
||||
|
||||
typedef struct SColumnFilterElem {
|
||||
|
@ -90,98 +87,111 @@ typedef struct SColumnFilterElem {
|
|||
} SColumnFilterElem;
|
||||
|
||||
typedef struct SSingleColumnFilterInfo {
|
||||
SColumnInfo info;
|
||||
int32_t numOfFilters;
|
||||
SColumnFilterElem* pFilters;
|
||||
void* pData;
|
||||
int32_t numOfFilters;
|
||||
SColumnInfo info;
|
||||
SColumnFilterElem* pFilters;
|
||||
} SSingleColumnFilterInfo;
|
||||
|
||||
typedef struct STableQueryInfo { // todo merge with the STableQueryInfo struct
|
||||
int32_t tableIndex;
|
||||
int32_t groupIdx; // group id in table list
|
||||
int32_t groupIndex; // group id in table list
|
||||
TSKEY lastKey;
|
||||
int32_t numOfRes;
|
||||
int16_t queryRangeSet; // denote if the query range is set, only available for interval query
|
||||
int64_t tag;
|
||||
STimeWindow win;
|
||||
STSCursor cur;
|
||||
STableId id; // for retrieve the page id list
|
||||
|
||||
STableId id; // for retrieve the page id list
|
||||
|
||||
SWindowResInfo windowResInfo;
|
||||
} STableQueryInfo;
|
||||
|
||||
typedef struct SQueryCostSummary {
|
||||
} SQueryCostSummary;
|
||||
typedef struct SQueryCostInfo {
|
||||
uint64_t loadStatisTime;
|
||||
uint64_t loadFileBlockTime;
|
||||
uint64_t loadDataInCacheTime;
|
||||
uint64_t loadStatisSize;
|
||||
uint64_t loadFileBlockSize;
|
||||
uint64_t loadDataInCacheSize;
|
||||
|
||||
uint64_t loadDataTime;
|
||||
uint64_t dataInRows;
|
||||
uint64_t checkRows;
|
||||
uint32_t dataBlocks;
|
||||
uint32_t loadBlockStatis;
|
||||
uint32_t discardBlocks;
|
||||
} SQueryCostInfo;
|
||||
|
||||
typedef struct SGroupItem {
|
||||
STableId id;
|
||||
STableId id;
|
||||
STableQueryInfo* info;
|
||||
} SGroupItem;
|
||||
|
||||
typedef struct SQuery {
|
||||
int16_t numOfCols;
|
||||
int16_t numOfTags;
|
||||
|
||||
SOrderVal order;
|
||||
STimeWindow window;
|
||||
int64_t intervalTime;
|
||||
int64_t slidingTime; // sliding time for sliding window query
|
||||
char slidingTimeUnit; // interval data type, used for daytime revise
|
||||
int8_t precision;
|
||||
int16_t numOfOutput;
|
||||
int16_t fillType;
|
||||
int16_t checkBuffer; // check if the buffer is full during scan each block
|
||||
SLimitVal limit;
|
||||
int32_t rowSize;
|
||||
SSqlGroupbyExpr* pGroupbyExpr;
|
||||
SExprInfo* pSelectExpr;
|
||||
SColumnInfo* colList;
|
||||
SColumnInfo* tagColList;
|
||||
int32_t numOfFilterCols;
|
||||
int64_t* fillVal;
|
||||
uint32_t status; // query status
|
||||
SResultRec rec;
|
||||
int32_t pos;
|
||||
tFilePage** sdata;
|
||||
STableQueryInfo* current;
|
||||
int16_t numOfCols;
|
||||
int16_t numOfTags;
|
||||
SOrderVal order;
|
||||
STimeWindow window;
|
||||
int64_t intervalTime;
|
||||
int64_t slidingTime; // sliding time for sliding window query
|
||||
char slidingTimeUnit; // interval data type, used for daytime revise
|
||||
int16_t precision;
|
||||
int16_t numOfOutput;
|
||||
int16_t fillType;
|
||||
int16_t checkBuffer; // check if the buffer is full during scan each block
|
||||
SLimitVal limit;
|
||||
int32_t rowSize;
|
||||
SSqlGroupbyExpr* pGroupbyExpr;
|
||||
SExprInfo* pSelectExpr;
|
||||
SColumnInfo* colList;
|
||||
SColumnInfo* tagColList;
|
||||
int32_t numOfFilterCols;
|
||||
int64_t* fillVal;
|
||||
uint32_t status; // query status
|
||||
SResultRec rec;
|
||||
int32_t pos;
|
||||
tFilePage** sdata;
|
||||
STableQueryInfo* current;
|
||||
|
||||
SSingleColumnFilterInfo* pFilterInfo;
|
||||
} SQuery;
|
||||
|
||||
typedef struct SQueryRuntimeEnv {
|
||||
SResultInfo* resultInfo; // todo refactor to merge with SWindowResInfo
|
||||
SQuery* pQuery;
|
||||
SQLFunctionCtx* pCtx;
|
||||
int16_t numOfRowsPerPage;
|
||||
int16_t offset[TSDB_MAX_COLUMNS];
|
||||
uint16_t scanFlag; // denotes reversed scan of data or not
|
||||
SFillInfo* pFillInfo;
|
||||
SWindowResInfo windowResInfo;
|
||||
STSBuf* pTSBuf;
|
||||
STSCursor cur;
|
||||
SQueryCostSummary summary;
|
||||
bool stableQuery; // super table query or not
|
||||
void* pQueryHandle;
|
||||
void* pSecQueryHandle; // another thread for
|
||||
SDiskbasedResultBuf* pResultBuf; // query result buffer based on blocked-wised disk file
|
||||
SResultInfo* resultInfo; // todo refactor to merge with SWindowResInfo
|
||||
SQuery* pQuery;
|
||||
SQLFunctionCtx* pCtx;
|
||||
int16_t numOfRowsPerPage;
|
||||
int16_t offset[TSDB_MAX_COLUMNS];
|
||||
uint16_t scanFlag; // denotes reversed scan of data or not
|
||||
SFillInfo* pFillInfo;
|
||||
SWindowResInfo windowResInfo;
|
||||
STSBuf* pTSBuf;
|
||||
STSCursor cur;
|
||||
SQueryCostInfo summary;
|
||||
bool stableQuery; // super table query or not
|
||||
void* pQueryHandle;
|
||||
void* pSecQueryHandle; // another thread for
|
||||
SDiskbasedResultBuf* pResultBuf; // query result buffer based on blocked-wised disk file
|
||||
} SQueryRuntimeEnv;
|
||||
|
||||
typedef struct SQInfo {
|
||||
void* signature;
|
||||
TSKEY startTime;
|
||||
TSKEY elapsedTime;
|
||||
int32_t pointsInterpo;
|
||||
int32_t code; // error code to returned to client
|
||||
sem_t dataReady;
|
||||
void* tsdb;
|
||||
int32_t vgId;
|
||||
|
||||
void* signature;
|
||||
TSKEY startTime;
|
||||
TSKEY elapsedTime;
|
||||
int32_t pointsInterpo;
|
||||
int32_t code; // error code to returned to client
|
||||
sem_t dataReady;
|
||||
void* tsdb;
|
||||
int32_t vgId;
|
||||
|
||||
STableGroupInfo tableIdGroupInfo; // table id list < only includes the STableId list>
|
||||
STableGroupInfo groupInfo; //
|
||||
SQueryRuntimeEnv runtimeEnv;
|
||||
int32_t groupIndex;
|
||||
int32_t offset; // offset in group result set of subgroup, todo refactor
|
||||
int32_t offset; // offset in group result set of subgroup, todo refactor
|
||||
SArray* arrTableIdInfo;
|
||||
|
||||
|
||||
T_REF_DECLARE()
|
||||
/*
|
||||
* the query is executed position on which meter of the whole list.
|
||||
|
@ -189,8 +199,8 @@ typedef struct SQInfo {
|
|||
* We later may refactor to remove this attribution by using another flag to denote
|
||||
* whether a multimeter query is completed or not.
|
||||
*/
|
||||
int32_t tableIndex;
|
||||
int32_t numOfGroupResultPages;
|
||||
int32_t tableIndex;
|
||||
int32_t numOfGroupResultPages;
|
||||
} SQInfo;
|
||||
|
||||
#endif // TDENGINE_QUERYEXECUTOR_H
|
||||
|
|
|
@ -28,8 +28,7 @@ extern "C" {
|
|||
#include "tdataformat.h"
|
||||
#include "talgo.h"
|
||||
|
||||
#define DEFAULT_PAGE_SIZE 16384 // 16k larger than the SHistoInfo
|
||||
#define MIN_BUFFER_SIZE (1 << 19)
|
||||
#define DEFAULT_PAGE_SIZE (1024L*56) // 16k larger than the SHistoInfo
|
||||
#define MAX_TMPFILE_PATH_LENGTH PATH_MAX
|
||||
#define INITIAL_ALLOCATION_BUFFER_SIZE 64
|
||||
|
||||
|
|
|
@ -45,12 +45,13 @@ typedef struct SFillInfo {
|
|||
int32_t numOfCols; // number of columns, including the tags columns
|
||||
int32_t rowSize; // size of each row
|
||||
char ** pTags; // tags value for current interpolation
|
||||
|
||||
int64_t slidingTime; // sliding value to determine the number of result for a given time window
|
||||
int64_t slidingTime; // sliding value to determine the number of result for a given time window
|
||||
char * prevValues; // previous row of data, to generate the interpolation results
|
||||
char * nextValues; // next row of data
|
||||
char** pData; // original result data block involved in filling data
|
||||
int32_t capacityInRows; // data buffer size in rows
|
||||
|
||||
SFillColInfo* pFillCol; // column info for fill operations
|
||||
char** pData; // original result data block involved in filling data
|
||||
} SFillInfo;
|
||||
|
||||
typedef struct SPoint {
|
||||
|
|
|
@ -49,7 +49,7 @@ typedef struct tMemBucket {
|
|||
int32_t nTotalBufferSize;
|
||||
int32_t maxElemsCapacity;
|
||||
|
||||
int16_t pageSize;
|
||||
int32_t pageSize;
|
||||
int16_t numOfTotalPages;
|
||||
int16_t numOfAvailPages; /* remain available buffer pages */
|
||||
|
||||
|
|
|
@ -44,6 +44,8 @@ typedef struct SDiskbasedResultBuf {
|
|||
SIDList* list; // for each id, there is a page id list
|
||||
} SDiskbasedResultBuf;
|
||||
|
||||
#define DEFAULT_INTERN_BUF_PAGE_SIZE (8192L*5)
|
||||
|
||||
/**
|
||||
* create disk-based result buffer
|
||||
* @param pResultBuf
|
||||
|
|
|
@ -161,26 +161,24 @@ typedef struct SExtTagsInfo {
|
|||
|
||||
// sql function runtime context
|
||||
typedef struct SQLFunctionCtx {
|
||||
int32_t startOffset;
|
||||
int32_t size; // number of rows
|
||||
uint32_t order; // asc|desc
|
||||
uint32_t scanFlag; // TODO merge with currentStage
|
||||
|
||||
int16_t inputType;
|
||||
int16_t inputBytes;
|
||||
|
||||
int16_t outputType;
|
||||
int16_t outputBytes; // size of results, determined by function and input column data type
|
||||
bool hasNull; // null value exist in current block
|
||||
int16_t functionId; // function id
|
||||
void * aInputElemBuf;
|
||||
char * aOutputBuf; // final result output buffer, point to sdata->data
|
||||
uint8_t currentStage; // record current running step, default: 0
|
||||
int64_t nStartQueryTimestamp; // timestamp range of current query when function is executed on a specific data block
|
||||
int32_t numOfParams;
|
||||
tVariant param[4]; // input parameter, e.g., top(k, 20), the number of results for top query is kept in param */
|
||||
int64_t *ptsList; // corresponding timestamp array list
|
||||
void * ptsOutputBuf; // corresponding output buffer for timestamp of each result, e.g., top/bottom*/
|
||||
int32_t startOffset;
|
||||
int32_t size; // number of rows
|
||||
uint32_t order; // asc|desc
|
||||
int16_t inputType;
|
||||
int16_t inputBytes;
|
||||
|
||||
int16_t outputType;
|
||||
int16_t outputBytes; // size of results, determined by function and input column data type
|
||||
bool hasNull; // null value exist in current block
|
||||
int16_t functionId; // function id
|
||||
void * aInputElemBuf;
|
||||
char * aOutputBuf; // final result output buffer, point to sdata->data
|
||||
uint8_t currentStage; // record current running step, default: 0
|
||||
int64_t nStartQueryTimestamp; // timestamp range of current query when function is executed on a specific data block
|
||||
int32_t numOfParams;
|
||||
tVariant param[4]; // input parameter, e.g., top(k, 20), the number of results for top query is kept in param */
|
||||
int64_t * ptsList; // corresponding timestamp array list
|
||||
void * ptsOutputBuf; // corresponding output buffer for timestamp of each result, e.g., top/bottom*/
|
||||
SQLPreAggVal preAggVals;
|
||||
tVariant tag;
|
||||
SResultInfo *resultInfo;
|
||||
|
@ -219,7 +217,7 @@ typedef struct SQLAggFuncElem {
|
|||
#define GET_RES_INFO(ctx) ((ctx)->resultInfo)
|
||||
|
||||
int32_t getResultDataInfo(int32_t dataType, int32_t dataBytes, int32_t functionId, int32_t param, int16_t *type,
|
||||
int16_t *len, int16_t *interBytes, int16_t extLength, bool isSuperTable);
|
||||
int16_t *len, int32_t *interBytes, int16_t extLength, bool isSuperTable);
|
||||
|
||||
#define IS_STREAM_QUERY_VALID(x) (((x)&TSDB_FUNCSTATE_STREAM) != 0)
|
||||
#define IS_MULTIOUTPUT(x) (((x)&TSDB_FUNCSTATE_MO) != 0)
|
||||
|
@ -239,7 +237,7 @@ enum {
|
|||
/* determine the real data need to calculated the result */
|
||||
enum {
|
||||
BLK_DATA_NO_NEEDED = 0x0,
|
||||
BLK_DATA_FILEDS_NEEDED = 0x1,
|
||||
BLK_DATA_STATIS_NEEDED = 0x1,
|
||||
BLK_DATA_ALL_NEEDED = 0x3,
|
||||
};
|
||||
|
||||
|
@ -269,9 +267,6 @@ extern struct SQLAggFuncElem aAggs[];
|
|||
/* compatible check array list */
|
||||
extern int32_t funcCompatDefList[];
|
||||
|
||||
void getStatistics(char *priData, char *data, int32_t size, int32_t numOfRow, int32_t type, int64_t *min, int64_t *max,
|
||||
int64_t *sum, int16_t *minIndex, int16_t *maxIndex, int32_t *numOfNull);
|
||||
|
||||
bool top_bot_datablock_filter(SQLFunctionCtx *pCtx, int32_t functionId, char *minval, char *maxval);
|
||||
|
||||
bool stableQueryFunctChanged(int32_t funcId);
|
||||
|
|
|
@ -48,7 +48,7 @@ void tVariantAssign(tVariant *pDst, const tVariant *pSrc);
|
|||
|
||||
int32_t tVariantToString(tVariant *pVar, char *dst);
|
||||
|
||||
int32_t tVariantDump(tVariant *pVariant, char *payload, char type);
|
||||
int32_t tVariantDump(tVariant *pVariant, char *payload, int16_t type, bool includeLengthPrefix);
|
||||
|
||||
int32_t tVariantTypeSetType(tVariant *pVariant, char type);
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -209,7 +209,7 @@ bool like_str(SColumnFilterElem *pFilter, char *minval, char *maxval) {
|
|||
bool like_nchar(SColumnFilterElem* pFilter, char* minval, char *maxval) {
|
||||
SPatternCompareInfo info = PATTERN_COMPARE_INFO_INITIALIZER;
|
||||
|
||||
return WCSPatternMatch((wchar_t*) pFilter->filterInfo.pz, varDataVal(minval), varDataLen(minval)/TSDB_NCHAR_SIZE, &info) == TSDB_PATTERN_MATCH;
|
||||
return WCSPatternMatch((wchar_t*)pFilter->filterInfo.pz, varDataVal(minval), varDataLen(minval)/TSDB_NCHAR_SIZE, &info) == TSDB_PATTERN_MATCH;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -137,11 +137,10 @@ void clearFirstNTimeWindow(SQueryRuntimeEnv *pRuntimeEnv, int32_t num) {
|
|||
for (int32_t k = 0; k < pWindowResInfo->size; ++k) {
|
||||
SWindowResult *pResult = &pWindowResInfo->pResult[k];
|
||||
int32_t *p = (int32_t *)taosHashGet(pWindowResInfo->hashList, (const char *)&pResult->window.skey, TSDB_KEYSIZE);
|
||||
|
||||
int32_t v = (*p - num);
|
||||
assert(v >= 0 && v <= pWindowResInfo->size);
|
||||
|
||||
taosHashPut(pWindowResInfo->hashList, (const char *)&pResult->window.skey, TSDB_KEYSIZE, (char *)&v,
|
||||
sizeof(int32_t));
|
||||
taosHashPut(pWindowResInfo->hashList, (char *)&pResult->window.skey, TSDB_KEYSIZE, (char *)&v, sizeof(int32_t));
|
||||
}
|
||||
|
||||
pWindowResInfo->curIndex = -1;
|
||||
|
|
|
@ -79,7 +79,7 @@ SFillInfo* taosInitFillInfo(int32_t order, TSKEY skey, int32_t numOfTags, int32_
|
|||
int32_t rowsize = 0;
|
||||
for (int32_t i = 0; i < numOfCols; ++i) {
|
||||
int32_t bytes = pFillInfo->pFillCol[i].col.bytes;
|
||||
pFillInfo->pData[i] = calloc(1, sizeof(tFilePage) + bytes * capacity);
|
||||
pFillInfo->pData[i] = calloc(1, bytes * capacity);
|
||||
|
||||
rowsize += bytes;
|
||||
}
|
||||
|
@ -89,6 +89,8 @@ SFillInfo* taosInitFillInfo(int32_t order, TSKEY skey, int32_t numOfTags, int32_
|
|||
}
|
||||
|
||||
pFillInfo->rowSize = rowsize;
|
||||
pFillInfo->capacityInRows = capacity;
|
||||
|
||||
return pFillInfo;
|
||||
}
|
||||
|
||||
|
@ -119,6 +121,17 @@ void taosFillSetStartInfo(SFillInfo* pFillInfo, int32_t numOfRows, TSKEY endKey)
|
|||
pFillInfo->rowIdx = 0;
|
||||
pFillInfo->endKey = endKey;
|
||||
pFillInfo->numOfRows = numOfRows;
|
||||
|
||||
// ensure the space
|
||||
if (pFillInfo->capacityInRows < numOfRows) {
|
||||
for(int32_t i = 0; i < pFillInfo->numOfCols; ++i) {
|
||||
char* tmp = realloc(pFillInfo->pData[i], numOfRows*pFillInfo->pFillCol[i].col.bytes);
|
||||
assert(tmp != NULL); // todo handle error
|
||||
|
||||
memset(tmp, 0, numOfRows*pFillInfo->pFillCol[i].col.bytes);
|
||||
pFillInfo->pData[i] = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void taosFillCopyInputDataFromFilePage(SFillInfo* pFillInfo, tFilePage** pInput) {
|
||||
|
@ -474,11 +487,11 @@ int32_t generateDataBlockImpl(SFillInfo* pFillInfo, tFilePage** data, int32_t nu
|
|||
}
|
||||
|
||||
int64_t taosGenerateDataBlock(SFillInfo* pFillInfo, tFilePage** output, int32_t capacity) {
|
||||
int32_t remain = taosNumOfRemainRows(pFillInfo); // todo use iterator?
|
||||
int32_t rows = taosGetNumOfResultWithFill(pFillInfo, remain, pFillInfo->endKey, capacity);
|
||||
int32_t remain = taosNumOfRemainRows(pFillInfo); // todo use iterator?
|
||||
int32_t rows = taosGetNumOfResultWithFill(pFillInfo, remain, pFillInfo->endKey, capacity);
|
||||
|
||||
int32_t numOfRes = generateDataBlockImpl(pFillInfo, output, remain, rows, pFillInfo->pData);
|
||||
assert(numOfRes == rows);
|
||||
|
||||
int32_t numOfRes = generateDataBlockImpl(pFillInfo, output, remain, rows, pFillInfo->pData);
|
||||
assert(numOfRes == rows);
|
||||
|
||||
return numOfRes;
|
||||
return numOfRes;
|
||||
}
|
||||
|
|
|
@ -5,14 +5,12 @@
|
|||
#include "tsqlfunction.h"
|
||||
#include "queryLog.h"
|
||||
|
||||
#define DEFAULT_INTERN_BUF_SIZE 16384L
|
||||
|
||||
int32_t createDiskbasedResultBuffer(SDiskbasedResultBuf** pResultBuf, int32_t size, int32_t rowSize, void* handle) {
|
||||
SDiskbasedResultBuf* pResBuf = calloc(1, sizeof(SDiskbasedResultBuf));
|
||||
pResBuf->numOfRowsPerPage = (DEFAULT_INTERN_BUF_SIZE - sizeof(tFilePage)) / rowSize;
|
||||
pResBuf->numOfRowsPerPage = (DEFAULT_INTERN_BUF_PAGE_SIZE - sizeof(tFilePage)) / rowSize;
|
||||
pResBuf->numOfPages = size;
|
||||
|
||||
pResBuf->totalBufSize = pResBuf->numOfPages * DEFAULT_INTERN_BUF_SIZE;
|
||||
pResBuf->totalBufSize = pResBuf->numOfPages * DEFAULT_INTERN_BUF_PAGE_SIZE;
|
||||
pResBuf->incStep = 4;
|
||||
|
||||
// init id hash table
|
||||
|
@ -33,7 +31,7 @@ int32_t createDiskbasedResultBuffer(SDiskbasedResultBuf** pResultBuf, int32_t si
|
|||
return TSDB_CODE_CLI_NO_DISKSPACE;
|
||||
}
|
||||
|
||||
int32_t ret = ftruncate(pResBuf->fd, pResBuf->numOfPages * DEFAULT_INTERN_BUF_SIZE);
|
||||
int32_t ret = ftruncate(pResBuf->fd, pResBuf->numOfPages * DEFAULT_INTERN_BUF_PAGE_SIZE);
|
||||
if (ret != TSDB_CODE_SUCCESS) {
|
||||
qError("failed to create tmp file: %s on disk. %s", pResBuf->path, strerror(errno));
|
||||
return TSDB_CODE_CLI_NO_DISKSPACE;
|
||||
|
@ -55,7 +53,7 @@ int32_t createDiskbasedResultBuffer(SDiskbasedResultBuf** pResultBuf, int32_t si
|
|||
tFilePage* getResultBufferPageById(SDiskbasedResultBuf* pResultBuf, int32_t id) {
|
||||
assert(id < pResultBuf->numOfPages && id >= 0);
|
||||
|
||||
return (tFilePage*)(pResultBuf->pBuf + DEFAULT_INTERN_BUF_SIZE * id);
|
||||
return (tFilePage*)(pResultBuf->pBuf + DEFAULT_INTERN_BUF_PAGE_SIZE * id);
|
||||
}
|
||||
|
||||
int32_t getNumOfResultBufGroupId(SDiskbasedResultBuf* pResultBuf) { return taosHashGetSize(pResultBuf->idsTable); }
|
||||
|
@ -63,7 +61,7 @@ int32_t getNumOfResultBufGroupId(SDiskbasedResultBuf* pResultBuf) { return taosH
|
|||
int32_t getResBufSize(SDiskbasedResultBuf* pResultBuf) { return pResultBuf->totalBufSize; }
|
||||
|
||||
static int32_t extendDiskFileSize(SDiskbasedResultBuf* pResultBuf, int32_t numOfPages) {
|
||||
assert(pResultBuf->numOfPages * DEFAULT_INTERN_BUF_SIZE == pResultBuf->totalBufSize);
|
||||
assert(pResultBuf->numOfPages * DEFAULT_INTERN_BUF_PAGE_SIZE == pResultBuf->totalBufSize);
|
||||
|
||||
int32_t ret = munmap(pResultBuf->pBuf, pResultBuf->totalBufSize);
|
||||
pResultBuf->numOfPages += numOfPages;
|
||||
|
@ -72,14 +70,14 @@ static int32_t extendDiskFileSize(SDiskbasedResultBuf* pResultBuf, int32_t numOf
|
|||
* disk-based output buffer is exhausted, try to extend the disk-based buffer, the available disk space may
|
||||
* be insufficient
|
||||
*/
|
||||
ret = ftruncate(pResultBuf->fd, pResultBuf->numOfPages * DEFAULT_INTERN_BUF_SIZE);
|
||||
ret = ftruncate(pResultBuf->fd, pResultBuf->numOfPages * DEFAULT_INTERN_BUF_PAGE_SIZE);
|
||||
if (ret != 0) {
|
||||
// dError("QInfo:%p failed to create intermediate result output file:%s. %s", pQInfo, pSupporter->extBufFile,
|
||||
// strerror(errno));
|
||||
return -TSDB_CODE_SERV_NO_DISKSPACE;
|
||||
}
|
||||
|
||||
pResultBuf->totalBufSize = pResultBuf->numOfPages * DEFAULT_INTERN_BUF_SIZE;
|
||||
pResultBuf->totalBufSize = pResultBuf->numOfPages * DEFAULT_INTERN_BUF_PAGE_SIZE;
|
||||
pResultBuf->pBuf = mmap(NULL, pResultBuf->totalBufSize, PROT_READ | PROT_WRITE, MAP_SHARED, pResultBuf->fd, 0);
|
||||
|
||||
if (pResultBuf->pBuf == MAP_FAILED) {
|
||||
|
@ -174,7 +172,7 @@ tFilePage* getNewDataBuf(SDiskbasedResultBuf* pResultBuf, int32_t groupId, int32
|
|||
tFilePage* page = getResultBufferPageById(pResultBuf, *pageId);
|
||||
|
||||
// clear memory for the new page
|
||||
memset(page, 0, DEFAULT_INTERN_BUF_SIZE);
|
||||
memset(page, 0, DEFAULT_INTERN_BUF_PAGE_SIZE);
|
||||
|
||||
return page;
|
||||
}
|
||||
|
|
|
@ -363,8 +363,6 @@ static int32_t toBinary(tVariant *pVariant, char **pDest, int32_t *pDestSize) {
|
|||
|
||||
taosUcs4ToMbs(pVariant->wpz, newSize, pBuf);
|
||||
free(pVariant->wpz);
|
||||
|
||||
/* terminated string */
|
||||
pBuf[newSize] = 0;
|
||||
} else {
|
||||
taosUcs4ToMbs(pVariant->wpz, newSize, *pDest);
|
||||
|
@ -598,7 +596,7 @@ static int32_t convertToBool(tVariant *pVariant, int64_t *pDest) {
|
|||
*
|
||||
* todo handle the return value
|
||||
*/
|
||||
int32_t tVariantDump(tVariant *pVariant, char *payload, char type) {
|
||||
int32_t tVariantDump(tVariant *pVariant, char *payload, int16_t type, bool includeLengthPrefix) {
|
||||
if (pVariant == NULL || (pVariant->nType != 0 && !isValidDataType(pVariant->nType, pVariant->nLen))) {
|
||||
return -1;
|
||||
}
|
||||
|
@ -765,13 +763,30 @@ int32_t tVariantDump(tVariant *pVariant, char *payload, char type) {
|
|||
}
|
||||
|
||||
case TSDB_DATA_TYPE_BINARY: {
|
||||
if (pVariant->nType == TSDB_DATA_TYPE_NULL) {
|
||||
*payload = TSDB_DATA_BINARY_NULL;
|
||||
} else {
|
||||
if (pVariant->nType != TSDB_DATA_TYPE_BINARY) {
|
||||
toBinary(pVariant, &payload, &pVariant->nLen);
|
||||
if (!includeLengthPrefix) {
|
||||
if (pVariant->nType == TSDB_DATA_TYPE_NULL) {
|
||||
*(uint8_t*) payload = TSDB_DATA_BINARY_NULL;
|
||||
} else {
|
||||
strncpy(payload, pVariant->pz, pVariant->nLen);
|
||||
if (pVariant->nType != TSDB_DATA_TYPE_BINARY) {
|
||||
toBinary(pVariant, &payload, &pVariant->nLen);
|
||||
} else {
|
||||
strncpy(payload, pVariant->pz, pVariant->nLen);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (pVariant->nType == TSDB_DATA_TYPE_NULL) {
|
||||
setVardataNull(payload, TSDB_DATA_TYPE_BINARY);
|
||||
} else {
|
||||
char *p = varDataVal(payload);
|
||||
|
||||
if (pVariant->nType != TSDB_DATA_TYPE_BINARY) {
|
||||
toBinary(pVariant, &p, &pVariant->nLen);
|
||||
} else {
|
||||
strncpy(p, pVariant->pz, pVariant->nLen);
|
||||
}
|
||||
|
||||
varDataSetLen(payload, pVariant->nLen);
|
||||
assert(p == varDataVal(payload));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -785,15 +800,33 @@ int32_t tVariantDump(tVariant *pVariant, char *payload, char type) {
|
|||
break;
|
||||
}
|
||||
case TSDB_DATA_TYPE_NCHAR: {
|
||||
if (pVariant->nType == TSDB_DATA_TYPE_NULL) {
|
||||
*(uint32_t *) payload = TSDB_DATA_NCHAR_NULL;
|
||||
} else {
|
||||
if (pVariant->nType != TSDB_DATA_TYPE_NCHAR) {
|
||||
toNchar(pVariant, &payload, &pVariant->nLen);
|
||||
if (!includeLengthPrefix) {
|
||||
if (pVariant->nType == TSDB_DATA_TYPE_NULL) {
|
||||
*(uint32_t *)payload = TSDB_DATA_NCHAR_NULL;
|
||||
} else {
|
||||
wcsncpy((wchar_t *)payload, pVariant->wpz, pVariant->nLen);
|
||||
if (pVariant->nType != TSDB_DATA_TYPE_NCHAR) {
|
||||
toNchar(pVariant, &payload, &pVariant->nLen);
|
||||
} else {
|
||||
wcsncpy((wchar_t *)payload, pVariant->wpz, pVariant->nLen);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (pVariant->nType == TSDB_DATA_TYPE_NULL) {
|
||||
setVardataNull(payload, TSDB_DATA_TYPE_NCHAR);
|
||||
} else {
|
||||
char *p = varDataVal(payload);
|
||||
|
||||
if (pVariant->nType != TSDB_DATA_TYPE_NCHAR) {
|
||||
toNchar(pVariant, &p, &pVariant->nLen);
|
||||
} else {
|
||||
wcsncpy((wchar_t *)p, pVariant->wpz, pVariant->nLen);
|
||||
}
|
||||
|
||||
varDataSetLen(payload, pVariant->nLen); // the length may be changed after toNchar function called
|
||||
assert(p == varDataVal(payload));
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -124,8 +124,7 @@ typedef struct SRpcConn {
|
|||
} SRpcConn;
|
||||
|
||||
int tsRpcMaxUdpSize = 15000; // bytes
|
||||
int tsRpcProgressTime = 10; // milliseocnds
|
||||
|
||||
int tsProgressTimer = 100;
|
||||
// not configurable
|
||||
int tsRpcMaxRetry;
|
||||
int tsRpcHeadSize;
|
||||
|
@ -204,7 +203,8 @@ static void rpcUnlockConn(SRpcConn *pConn);
|
|||
void *rpcOpen(const SRpcInit *pInit) {
|
||||
SRpcInfo *pRpc;
|
||||
|
||||
tsRpcMaxRetry = tsRpcMaxTime * 1000 / tsRpcProgressTime;
|
||||
tsProgressTimer = tsRpcTimer/2;
|
||||
tsRpcMaxRetry = tsRpcMaxTime * 1000/tsProgressTimer;
|
||||
tsRpcHeadSize = RPC_MSG_OVERHEAD;
|
||||
tsRpcOverhead = sizeof(SRpcReqContext);
|
||||
|
||||
|
@ -420,8 +420,11 @@ void rpcSendResponse(const SRpcMsg *pRsp) {
|
|||
pConn->rspMsgLen = msgLen;
|
||||
if (pMsg->code == TSDB_CODE_ACTION_IN_PROGRESS) pConn->inTranId--;
|
||||
|
||||
SRpcInfo *pRpc = pConn->pRpc;
|
||||
taosTmrStopA(&pConn->pTimer);
|
||||
// taosTmrReset(rpcProcessIdleTimer, pRpc->idleTime, pConn, pRpc->tmrCtrl, &pConn->pIdleTimer);
|
||||
|
||||
// set the idle timer to monitor the activity
|
||||
taosTmrReset(rpcProcessIdleTimer, pRpc->idleTime, pConn, pRpc->tmrCtrl, &pConn->pIdleTimer);
|
||||
rpcSendMsgToPeer(pConn, msg, msgLen);
|
||||
pConn->secured = 1; // connection shall be secured
|
||||
|
||||
|
@ -677,8 +680,10 @@ static SRpcConn *rpcSetupConnToServer(SRpcReqContext *pContext) {
|
|||
}
|
||||
|
||||
if (pConn) {
|
||||
pConn->tretry = 0;
|
||||
pConn->ahandle = pContext->ahandle;
|
||||
sprintf(pConn->info, "%s %p %p", pRpc->label, pConn, pConn->ahandle);
|
||||
pConn->tretry = 0;
|
||||
} else {
|
||||
tError("%s %p, failed to set up connection(%s)", pRpc->label, pContext->ahandle, tstrerror(terrno));
|
||||
}
|
||||
|
@ -748,20 +753,28 @@ static int rpcProcessRspHead(SRpcConn *pConn, SRpcHead *pHead) {
|
|||
taosTmrStopA(&pConn->pTimer);
|
||||
pConn->retry = 0;
|
||||
|
||||
if (pHead->code == TSDB_CODE_AUTH_REQUIRED && pRpc->spi) {
|
||||
tTrace("%s, authentication shall be restarted", pConn->info);
|
||||
pConn->secured = 0;
|
||||
rpcSendMsgToPeer(pConn, pConn->pReqMsg, pConn->reqMsgLen);
|
||||
pConn->pTimer = taosTmrStart(rpcProcessRetryTimer, tsRpcTimer, pConn, pRpc->tmrCtrl);
|
||||
return TSDB_CODE_ALREADY_PROCESSED;
|
||||
}
|
||||
|
||||
if (pHead->code == TSDB_CODE_ACTION_IN_PROGRESS) {
|
||||
if (pConn->tretry <= tsRpcMaxRetry) {
|
||||
tTrace("%s, peer is still processing the transaction", pConn->info);
|
||||
tTrace("%s, peer is still processing the transaction, retry:%d", pConn->info, pConn->tretry);
|
||||
pConn->tretry++;
|
||||
rpcSendReqHead(pConn);
|
||||
taosTmrReset(rpcProcessRetryTimer, tsRpcTimer, pConn, pRpc->tmrCtrl, &pConn->pTimer);
|
||||
pConn->pTimer = taosTmrStart(rpcProcessRetryTimer, tsRpcTimer, pConn, pRpc->tmrCtrl);
|
||||
return TSDB_CODE_ALREADY_PROCESSED;
|
||||
} else {
|
||||
// peer still in processing, give up
|
||||
return TSDB_CODE_TOO_SLOW;
|
||||
tTrace("%s, server processing takes too long time, give up", pConn->info);
|
||||
pHead->code = TSDB_CODE_TOO_SLOW;
|
||||
}
|
||||
}
|
||||
|
||||
pConn->tretry = 0;
|
||||
pConn->outType = 0;
|
||||
pConn->pReqMsg = NULL;
|
||||
pConn->reqMsgLen = 0;
|
||||
|
@ -790,7 +803,7 @@ static SRpcConn *rpcProcessMsgHead(SRpcInfo *pRpc, SRecvInfo *pRecv) {
|
|||
|
||||
pConn = rpcGetConnObj(pRpc, sid, pRecv);
|
||||
if (pConn == NULL) {
|
||||
tError("%s %p, failed to get connection obj(%s)", pRpc->label, pHead->ahandle, tstrerror(terrno));
|
||||
tTrace("%s %p, failed to get connection obj(%s)", pRpc->label, pHead->ahandle, tstrerror(terrno));
|
||||
return NULL;
|
||||
} else {
|
||||
if (rpcIsReq(pHead->msgType)) {
|
||||
|
@ -820,7 +833,9 @@ static SRpcConn *rpcProcessMsgHead(SRpcInfo *pRpc, SRecvInfo *pRecv) {
|
|||
if ( rpcIsReq(pHead->msgType) ) {
|
||||
terrno = rpcProcessReqHead(pConn, pHead);
|
||||
pConn->connType = pRecv->connType;
|
||||
taosTmrReset(rpcProcessIdleTimer, pRpc->idleTime, pConn, pRpc->tmrCtrl, &pConn->pIdleTimer);
|
||||
|
||||
// client shall send the request within tsRpcTime again, double it
|
||||
taosTmrReset(rpcProcessIdleTimer, tsRpcTimer*2, pConn, pRpc->tmrCtrl, &pConn->pIdleTimer);
|
||||
} else {
|
||||
terrno = rpcProcessRspHead(pConn, pHead);
|
||||
}
|
||||
|
@ -935,7 +950,7 @@ static void rpcProcessIncomingMsg(SRpcConn *pConn, SRpcHead *pHead) {
|
|||
|
||||
if ( rpcIsReq(pHead->msgType) ) {
|
||||
rpcMsg.handle = pConn;
|
||||
taosTmrReset(rpcProcessProgressTimer, tsRpcTimer/2, pConn, pRpc->tmrCtrl, &pConn->pTimer);
|
||||
pConn->pTimer = taosTmrStart(rpcProcessProgressTimer, tsProgressTimer, pConn, pRpc->tmrCtrl);
|
||||
(*(pRpc->cfp))(&rpcMsg, NULL);
|
||||
} else {
|
||||
// it's a response
|
||||
|
@ -943,14 +958,12 @@ static void rpcProcessIncomingMsg(SRpcConn *pConn, SRpcHead *pHead) {
|
|||
rpcMsg.handle = pContext->ahandle;
|
||||
pConn->pContext = NULL;
|
||||
|
||||
if (pHead->code == TSDB_CODE_AUTH_REQUIRED) {
|
||||
pConn->secured = 0;
|
||||
rpcSendReqToServer(pRpc, pContext);
|
||||
return;
|
||||
}
|
||||
|
||||
// for UDP, port may be changed by server, the port in ipSet shall be used for cache
|
||||
rpcAddConnIntoCache(pRpc->pCache, pConn, pConn->peerFqdn, pContext->ipSet.port[pContext->ipSet.inUse], pConn->connType);
|
||||
if (pHead->code != TSDB_CODE_TOO_SLOW) {
|
||||
rpcAddConnIntoCache(pRpc->pCache, pConn, pConn->peerFqdn, pContext->ipSet.port[pContext->ipSet.inUse], pConn->connType);
|
||||
} else {
|
||||
rpcCloseConn(pConn);
|
||||
}
|
||||
|
||||
if (pHead->code == TSDB_CODE_REDIRECT) {
|
||||
pContext->redirect++;
|
||||
|
@ -1039,6 +1052,7 @@ static void rpcSendErrorMsgToPeer(SRecvInfo *pRecv, int32_t code) {
|
|||
pReplyHead->sourceId = pRecvHead->destId;
|
||||
pReplyHead->destId = pRecvHead->sourceId;
|
||||
pReplyHead->linkUid = pRecvHead->linkUid;
|
||||
pReplyHead->ahandle = pRecvHead->ahandle;
|
||||
|
||||
pReplyHead->code = htonl(code);
|
||||
msgLen = sizeof(SRpcHead);
|
||||
|
@ -1086,7 +1100,7 @@ static void rpcSendReqToServer(SRpcInfo *pRpc, SRpcReqContext *pContext) {
|
|||
pHead->port = 0;
|
||||
pHead->linkUid = pConn->linkUid;
|
||||
pHead->ahandle = (uint64_t)pConn->ahandle;
|
||||
if (!pConn->secured) memcpy(pHead->user, pConn->user, tListLen(pHead->user));
|
||||
memcpy(pHead->user, pConn->user, tListLen(pHead->user));
|
||||
|
||||
// set the connection parameters
|
||||
pConn->outType = msgType;
|
||||
|
@ -1095,8 +1109,8 @@ static void rpcSendReqToServer(SRpcInfo *pRpc, SRpcReqContext *pContext) {
|
|||
pConn->reqMsgLen = msgLen;
|
||||
pConn->pContext = pContext;
|
||||
|
||||
taosTmrReset(rpcProcessRetryTimer, tsRpcTimer, pConn, pRpc->tmrCtrl, &pConn->pTimer);
|
||||
rpcSendMsgToPeer(pConn, msg, msgLen);
|
||||
taosTmrReset(rpcProcessRetryTimer, tsRpcTimer, pConn, pRpc->tmrCtrl, &pConn->pTimer);
|
||||
|
||||
rpcUnlockConn(pConn);
|
||||
}
|
||||
|
@ -1172,7 +1186,7 @@ static void rpcProcessRetryTimer(void *param, void *tmrId) {
|
|||
if (pConn->retry < 4) {
|
||||
tTrace("%s, re-send msg:%s to %s:%hu", pConn->info, taosMsg[pConn->outType], pConn->peerFqdn, pConn->peerPort);
|
||||
rpcSendMsgToPeer(pConn, pConn->pReqMsg, pConn->reqMsgLen);
|
||||
taosTmrReset(rpcProcessRetryTimer, tsRpcTimer, pConn, pRpc->tmrCtrl, &pConn->pTimer);
|
||||
pConn->pTimer = taosTmrStart(rpcProcessRetryTimer, tsRpcTimer, pConn, pRpc->tmrCtrl);
|
||||
} else {
|
||||
// close the connection
|
||||
tTrace("%s, failed to send msg:%s to %s:%hu", pConn->info, taosMsg[pConn->outType], pConn->peerFqdn, pConn->peerPort);
|
||||
|
@ -1225,7 +1239,7 @@ static void rpcProcessProgressTimer(void *param, void *tmrId) {
|
|||
if (pConn->inType && pConn->user[0]) {
|
||||
tTrace("%s, progress timer expired, send progress", pConn->info);
|
||||
rpcSendQuickRsp(pConn, TSDB_CODE_ACTION_IN_PROGRESS);
|
||||
taosTmrReset(rpcProcessProgressTimer, tsRpcTimer/2, pConn, pRpc->tmrCtrl, &pConn->pTimer);
|
||||
pConn->pTimer = taosTmrStart(rpcProcessProgressTimer, tsProgressTimer, pConn, pRpc->tmrCtrl);
|
||||
} else {
|
||||
tTrace("%s, progress timer:%p not processed", pConn->info, tmrId);
|
||||
}
|
||||
|
@ -1357,15 +1371,17 @@ static int rpcCheckAuthentication(SRpcConn *pConn, char *msg, int msgLen) {
|
|||
if ((pConn->secured && pHead->spi == 0) || (pHead->spi == 0 && pConn->spi == 0)){
|
||||
// secured link, or no authentication
|
||||
pHead->msgLen = (int32_t)htonl((uint32_t)pHead->msgLen);
|
||||
// tTrace("%s, secured link, no auth is required", pConn->info);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ( !rpcIsReq(pHead->msgType) ) {
|
||||
// for response, if code is auth failure, it shall bypass the auth process
|
||||
code = htonl(pHead->code);
|
||||
if (code==TSDB_CODE_INVALID_TIME_STAMP || code==TSDB_CODE_AUTH_FAILURE ||
|
||||
if (code==TSDB_CODE_INVALID_TIME_STAMP || code==TSDB_CODE_AUTH_FAILURE || code == TSDB_CODE_AUTH_REQUIRED ||
|
||||
code==TSDB_CODE_INVALID_USER || code == TSDB_CODE_NOT_READY) {
|
||||
pHead->msgLen = (int32_t)htonl((uint32_t)pHead->msgLen);
|
||||
// tTrace("%s, dont check authentication since code is:0x%x", pConn->info, code);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -1383,17 +1399,17 @@ static int rpcCheckAuthentication(SRpcConn *pConn, char *msg, int msgLen) {
|
|||
code = TSDB_CODE_INVALID_TIME_STAMP;
|
||||
} else {
|
||||
if (rpcAuthenticateMsg(pHead, msgLen-TSDB_AUTH_LEN, pDigest->auth, pConn->secret) < 0) {
|
||||
tError("%s, authentication failed, msg discarded", pConn->info);
|
||||
tTrace("%s, authentication failed, msg discarded", pConn->info);
|
||||
code = TSDB_CODE_AUTH_FAILURE;
|
||||
} else {
|
||||
pHead->msgLen = (int32_t)htonl((uint32_t)pHead->msgLen) - sizeof(SRpcDigest);
|
||||
if ( !rpcIsReq(pHead->msgType) ) pConn->secured = 1; // link is secured for client
|
||||
//tTrace("%s, message is authenticated", pConn->info);
|
||||
// tTrace("%s, message is authenticated", pConn->info);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
tError("%s, auth spi:%d not matched with received:%d", pConn->info, pConn->spi, pHead->spi);
|
||||
code = TSDB_CODE_AUTH_FAILURE;
|
||||
tTrace("%s, auth spi:%d not matched with received:%d", pConn->info, pConn->spi, pHead->spi);
|
||||
code = pHead->spi ? TSDB_CODE_AUTH_FAILURE : TSDB_CODE_AUTH_REQUIRED;
|
||||
}
|
||||
|
||||
return code;
|
||||
|
|
|
@ -380,7 +380,7 @@ static void *taosProcessTcpData(void *param) {
|
|||
|
||||
int32_t headLen = taosReadMsg(pFdObj->fd, &rpcHead, sizeof(SRpcHead));
|
||||
if (headLen != sizeof(SRpcHead)) {
|
||||
tError("%s %p, read error, headLen:%d", pThreadObj->label, pFdObj->thandle, headLen);
|
||||
tTrace("%s %p, read error, headLen:%d", pThreadObj->label, pFdObj->thandle, headLen);
|
||||
taosReportBrokenLink(pFdObj);
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ void processShellMsg() {
|
|||
while (1) {
|
||||
int numOfMsgs = taosReadAllQitems(qhandle, qall);
|
||||
if (numOfMsgs <= 0) {
|
||||
usleep(1000);
|
||||
usleep(100);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -115,7 +115,7 @@ int retrieveAuthInfo(char *meterId, char *spi, char *encrypt, char *secret, char
|
|||
|
||||
void processRequestMsg(SRpcMsg *pMsg, SRpcIpSet *pIpSet) {
|
||||
SRpcMsg *pTemp;
|
||||
|
||||
|
||||
pTemp = taosAllocateQitem(sizeof(SRpcMsg));
|
||||
memcpy(pTemp, pMsg, sizeof(SRpcMsg));
|
||||
|
||||
|
@ -171,7 +171,6 @@ int main(int argc, char *argv[]) {
|
|||
|
||||
tsAsyncLog = 0;
|
||||
rpcInit.connType = TAOS_CONN_SERVER;
|
||||
|
||||
taosInitLog("server.log", 100000, 10);
|
||||
|
||||
void *pRpc = rpcOpen(&rpcInit);
|
||||
|
|
|
@ -76,7 +76,7 @@ typedef struct STable {
|
|||
int32_t sversion;
|
||||
STSchema * schema;
|
||||
STSchema * tagSchema;
|
||||
SDataRow tagVal;
|
||||
SKVRow tagVal;
|
||||
SMemTable * mem;
|
||||
SMemTable * imem;
|
||||
void * pIndex; // For TSDB_SUPER_TABLE, it is the skiplist index
|
||||
|
|
|
@ -93,7 +93,7 @@ static int tsdbInitFile(char *dataDir, int fid, const char *suffix, SFile *pFile
|
|||
if (!taosCheckChecksumWhole((uint8_t *)buf, TSDB_FILE_HEAD_SIZE)) return -1;
|
||||
|
||||
void *pBuf = buf;
|
||||
pBuf = taosDecodeFixed32(pBuf, &version);
|
||||
pBuf = taosDecodeFixedU32(pBuf, &version);
|
||||
pBuf = tsdbDecodeSFileInfo(pBuf, &(pFile->info));
|
||||
|
||||
tsdbCloseFile(pFile);
|
||||
|
@ -287,7 +287,11 @@ int tsdbCopyBlockDataInFile(SFile *pOutFile, SFile *pInFile, SCompInfo *pCompInf
|
|||
int compFGroupKey(const void *key, const void *fgroup) {
|
||||
int fid = *(int *)key;
|
||||
SFileGroup *pFGroup = (SFileGroup *)fgroup;
|
||||
return (fid - pFGroup->fileId);
|
||||
if (fid == pFGroup->fileId) {
|
||||
return 0;
|
||||
} else {
|
||||
return fid > pFGroup->fileId? 1:-1;
|
||||
}
|
||||
}
|
||||
|
||||
static int compFGroup(const void *arg1, const void *arg2) {
|
||||
|
|
|
@ -9,8 +9,7 @@
|
|||
#include "ttime.h"
|
||||
#include <sys/stat.h>
|
||||
|
||||
#define TSDB_DEFAULT_PRECISION TSDB_PRECISION_MILLI // default precision
|
||||
#define IS_VALID_PRECISION(precision) (((precision) >= TSDB_PRECISION_MILLI) && ((precision) <= TSDB_PRECISION_NANO))
|
||||
#define IS_VALID_PRECISION(precision) (((precision) >= TSDB_TIME_PRECISION_MILLI) && ((precision) <= TSDB_TIME_PRECISION_NANO))
|
||||
#define TSDB_DEFAULT_COMPRESSION TWO_STAGE_COMP
|
||||
#define IS_VALID_COMPRESSION(compression) (((compression) >= NO_COMPRESSION) && ((compression) <= TWO_STAGE_COMP))
|
||||
#define TSDB_MIN_ID 0
|
||||
|
@ -79,6 +78,11 @@ void tsdbFreeCfg(STsdbCfg *pCfg) {
|
|||
if (pCfg != NULL) free(pCfg);
|
||||
}
|
||||
|
||||
STsdbCfg *tsdbGetCfg(const TsdbRepoT *repo) {
|
||||
assert(repo != NULL);
|
||||
return &((STsdbRepo*)repo)->config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new TSDB repository
|
||||
* @param rootDir the TSDB repository root directory
|
||||
|
@ -506,11 +510,11 @@ int tsdbTableSetTagSchema(STableCfg *config, STSchema *pSchema, bool dup) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int tsdbTableSetTagValue(STableCfg *config, SDataRow row, bool dup) {
|
||||
int tsdbTableSetTagValue(STableCfg *config, SKVRow row, bool dup) {
|
||||
if (config->type != TSDB_CHILD_TABLE) return -1;
|
||||
|
||||
if (dup) {
|
||||
config->tagValues = tdDataRowDup(row);
|
||||
config->tagValues = tdKVRowDup(row);
|
||||
} else {
|
||||
config->tagValues = row;
|
||||
}
|
||||
|
@ -557,7 +561,7 @@ int tsdbTableSetStreamSql(STableCfg *config, char *sql, bool dup) {
|
|||
void tsdbClearTableCfg(STableCfg *config) {
|
||||
if (config->schema) tdFreeSchema(config->schema);
|
||||
if (config->tagSchema) tdFreeSchema(config->tagSchema);
|
||||
if (config->tagValues) tdFreeDataRow(config->tagValues);
|
||||
if (config->tagValues) kvRowFree(config->tagValues);
|
||||
tfree(config->name);
|
||||
tfree(config->sname);
|
||||
tfree(config->sql);
|
||||
|
|
|
@ -47,8 +47,7 @@ void tsdbEncodeTable(STable *pTable, char *buf, int *contLen) {
|
|||
ptr = tdEncodeSchema(ptr, pTable->schema);
|
||||
ptr = tdEncodeSchema(ptr, pTable->tagSchema);
|
||||
} else if (pTable->type == TSDB_CHILD_TABLE) {
|
||||
tdTagRowCpy(ptr, pTable->tagVal);
|
||||
ptr = POINTER_SHIFT(ptr, dataRowLen(pTable->tagVal) + ((STagRow *)pTable->tagVal)->dataLen);
|
||||
ptr = tdEncodeKVRow(ptr, pTable->tagVal);
|
||||
} else {
|
||||
ptr = tdEncodeSchema(ptr, pTable->schema);
|
||||
}
|
||||
|
@ -94,8 +93,7 @@ STable *tsdbDecodeTable(void *cont, int contLen) {
|
|||
pTable->schema = tdDecodeSchema(&ptr);
|
||||
pTable->tagSchema = tdDecodeSchema(&ptr);
|
||||
} else if (pTable->type == TSDB_CHILD_TABLE) {
|
||||
pTable->tagVal = tdTagRowDecode(ptr);
|
||||
ptr = POINTER_SHIFT(ptr, dataRowLen(pTable->tagVal) + ((STagRow *)pTable->tagVal)->dataLen);
|
||||
ptr = tdDecodeKVRow(ptr, &pTable->tagVal);
|
||||
} else {
|
||||
pTable->schema = tdDecodeSchema(&ptr);
|
||||
}
|
||||
|
@ -103,7 +101,8 @@ STable *tsdbDecodeTable(void *cont, int contLen) {
|
|||
if (pTable->type == TSDB_STREAM_TABLE) {
|
||||
ptr = taosDecodeString(ptr, &(pTable->sql));
|
||||
}
|
||||
|
||||
|
||||
pTable->lastKey = TSKEY_INITIAL_VAL;
|
||||
return pTable;
|
||||
}
|
||||
|
||||
|
@ -114,12 +113,9 @@ void tsdbFreeEncode(void *cont) {
|
|||
static char* getTagIndexKey(const void* pData) {
|
||||
STableIndexElem* elem = (STableIndexElem*) pData;
|
||||
|
||||
SDataRow row = elem->pTable->tagVal;
|
||||
STSchema* pSchema = tsdbGetTableTagSchema(elem->pMeta, elem->pTable);
|
||||
STColumn* pCol = &pSchema->columns[DEFAULT_TAG_INDEX_COLUMN];
|
||||
int16_t type = 0;
|
||||
void * res = tdQueryTagByID(row, pCol->colId,&type);
|
||||
ASSERT(type == pCol->type);
|
||||
void * res = tdGetKVRowValOfCol(elem->pTable->tagVal, pCol->colId);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -254,31 +250,24 @@ STSchema * tsdbGetTableTagSchema(STsdbMeta *pMeta, STable *pTable) {
|
|||
int32_t tsdbGetTableTagVal(TsdbRepoT* repo, STableId* id, int32_t colId, int16_t* type, int16_t* bytes, char** val) {
|
||||
STsdbMeta* pMeta = tsdbGetMeta(repo);
|
||||
STable* pTable = tsdbGetTableByUid(pMeta, id->uid);
|
||||
|
||||
STSchema *pSchema = tsdbGetTableTagSchema(pMeta, pTable);
|
||||
STColumn *pCol = tdGetColOfID(pSchema, colId);
|
||||
if (pCol == NULL) {
|
||||
return -1; // No matched tag volumn
|
||||
}
|
||||
|
||||
STSchema* pSchema = tsdbGetTableTagSchema(pMeta, pTable);
|
||||
STColumn* pCol = NULL;
|
||||
*val = tdGetKVRowValOfCol(pTable->tagVal, colId);
|
||||
*type = pCol->type;
|
||||
|
||||
// todo binary search
|
||||
for(int32_t col = 0; col < schemaNCols(pSchema); ++col) {
|
||||
STColumn* p = schemaColAt(pSchema, col);
|
||||
if (p->colId == colId) {
|
||||
pCol = p;
|
||||
break;
|
||||
if (*val != NULL) {
|
||||
if (IS_VAR_DATA_TYPE(*type)) {
|
||||
*bytes = varDataLen(*val);
|
||||
} else {
|
||||
*bytes = TYPE_BYTES[*type];
|
||||
}
|
||||
}
|
||||
|
||||
if (pCol == NULL) {
|
||||
return -1; // No matched tags. Maybe the modification of tags has not been done yet.
|
||||
}
|
||||
|
||||
SDataRow row = (SDataRow)pTable->tagVal;
|
||||
int16_t tagtype = 0;
|
||||
char* d = tdQueryTagByID(row, pCol->colId, &tagtype);
|
||||
//ASSERT((int8_t)tagtype == pCol->type)
|
||||
*val = d;
|
||||
*type = pCol->type;
|
||||
*bytes = pCol->bytes;
|
||||
|
||||
return TSDB_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -352,7 +341,7 @@ static STable *tsdbNewTable(STableCfg *pCfg, bool isSuper) {
|
|||
|
||||
if (pCfg->type == TSDB_CHILD_TABLE) {
|
||||
pTable->superUid = pCfg->superUid;
|
||||
pTable->tagVal = tdDataRowDup(pCfg->tagValues);
|
||||
pTable->tagVal = tdKVRowDup(pCfg->tagValues);
|
||||
} else if (pCfg->type == TSDB_NORMAL_TABLE) {
|
||||
pTable->superUid = -1;
|
||||
pTable->schema = tdDupSchema(pCfg->schema);
|
||||
|
@ -405,7 +394,9 @@ int tsdbCreateTable(TsdbRepoT *repo, STableCfg *pCfg) {
|
|||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
table->lastKey = TSKEY_INITIAL_VAL;
|
||||
|
||||
// Register to meta
|
||||
if (newSuper) {
|
||||
tsdbAddTableToMeta(pMeta, super, true);
|
||||
|
@ -447,6 +438,61 @@ STable *tsdbIsValidTableToInsert(STsdbMeta *pMeta, STableId tableId) {
|
|||
return pTable;
|
||||
}
|
||||
|
||||
STableCfg *tsdbCreateTableCfgFromMsg(SMDCreateTableMsg *pMsg) {
|
||||
if (pMsg == NULL) return NULL;
|
||||
SSchema * pSchema = (SSchema *)pMsg->data;
|
||||
int16_t numOfCols = htons(pMsg->numOfColumns);
|
||||
int16_t numOfTags = htons(pMsg->numOfTags);
|
||||
STSchemaBuilder schemaBuilder = {0};
|
||||
|
||||
STableCfg *pCfg = (STableCfg *)calloc(1, sizeof(STableCfg));
|
||||
if (pCfg == NULL) return NULL;
|
||||
|
||||
if (tsdbInitTableCfg(pCfg, pMsg->tableType, htobe64(pMsg->uid), htonl(pMsg->sid)) < 0) goto _err;
|
||||
if (tdInitTSchemaBuilder(&schemaBuilder, htonl(pMsg->sversion)) < 0) goto _err;
|
||||
|
||||
for (int i = 0; i < numOfCols; i++) {
|
||||
tdAddColToSchema(&schemaBuilder, pSchema[i].type, htons(pSchema[i].colId), htons(pSchema[i].bytes));
|
||||
}
|
||||
if (tsdbTableSetSchema(pCfg, tdGetSchemaFromBuilder(&schemaBuilder), false) < 0) goto _err;
|
||||
if (tsdbTableSetName(pCfg, pMsg->tableId, true) < 0) goto _err;
|
||||
|
||||
if (numOfTags > 0) {
|
||||
int accBytes = 0;
|
||||
char *pTagData = pMsg->data + (numOfCols + numOfTags) * sizeof(SSchema);
|
||||
|
||||
SKVRowBuilder kvRowBuilder = {0};
|
||||
tdResetTSchemaBuilder(&schemaBuilder, htonl(pMsg->tversion));
|
||||
if (tdInitKVRowBuilder(&kvRowBuilder) < 0) goto _err;
|
||||
for (int i = numOfCols; i < numOfCols + numOfTags; i++) {
|
||||
tdAddColToSchema(&schemaBuilder, pSchema[i].type, htons(pSchema[i].colId), htons(pSchema[i].bytes));
|
||||
tdAddColToKVRow(&kvRowBuilder, htons(pSchema[i].colId), pSchema[i].type, pTagData + accBytes);
|
||||
accBytes += htons(pSchema[i].bytes);
|
||||
}
|
||||
if (tsdbTableSetTagSchema(pCfg, tdGetSchemaFromBuilder(&schemaBuilder), false) < 0) goto _err;
|
||||
if (tsdbTableSetSName(pCfg, pMsg->superTableId, true) < 0) goto _err;
|
||||
if (tsdbTableSetSuperUid(pCfg, htobe64(pMsg->superTableUid)) < 0) goto _err;
|
||||
|
||||
tsdbTableSetTagValue(pCfg, tdGetKVRowFromBuilder(&kvRowBuilder), false);
|
||||
tdDestroyKVRowBuilder(&kvRowBuilder);
|
||||
}
|
||||
|
||||
if (pMsg->tableType == TSDB_STREAM_TABLE) {
|
||||
char *sql = pMsg->data + (numOfCols + numOfTags) * sizeof(SSchema);
|
||||
tsdbTableSetStreamSql(pCfg, sql, true);
|
||||
}
|
||||
|
||||
tdDestroyTSchemaBuilder(&schemaBuilder);
|
||||
|
||||
return pCfg;
|
||||
|
||||
_err:
|
||||
tdDestroyTSchemaBuilder(&schemaBuilder);
|
||||
tsdbClearTableCfg(pCfg);
|
||||
tfree(pCfg);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// int32_t tsdbDropTableImpl(STsdbMeta *pMeta, STableId tableId) {
|
||||
int tsdbDropTable(TsdbRepoT *repo, STableId tableId) {
|
||||
STsdbRepo *pRepo = (STsdbRepo *)repo;
|
||||
|
@ -487,7 +533,7 @@ static int tsdbFreeTable(STable *pTable) {
|
|||
if (pTable == NULL) return 0;
|
||||
|
||||
if (pTable->type == TSDB_CHILD_TABLE) {
|
||||
tdFreeTagRow(pTable->tagVal);
|
||||
kvRowFree(pTable->tagVal);
|
||||
} else {
|
||||
tdFreeSchema(pTable->schema);
|
||||
}
|
||||
|
@ -636,9 +682,7 @@ static int tsdbRemoveTableFromIndex(STsdbMeta *pMeta, STable *pTable) {
|
|||
STSchema* pSchema = tsdbGetTableTagSchema(pMeta, pTable);
|
||||
STColumn* pCol = &pSchema->columns[DEFAULT_TAG_INDEX_COLUMN];
|
||||
|
||||
int16_t tagtype = 0;
|
||||
char* key = tdQueryTagByID(pTable->tagVal, pCol->colId, &tagtype);
|
||||
ASSERT(pCol->type == tagtype);
|
||||
char* key = tdGetKVRowValOfCol(pTable->tagVal, pCol->colId);
|
||||
SArray* res = tSkipListGet(pSTable->pIndex, key);
|
||||
|
||||
size_t size = taosArrayGetSize(res);
|
||||
|
|
|
@ -237,20 +237,24 @@ int tsdbSetAndOpenHelperFile(SRWHelper *pHelper, SFileGroup *pGroup) {
|
|||
|
||||
int tsdbCloseHelperFile(SRWHelper *pHelper, bool hasError) {
|
||||
if (pHelper->files.headF.fd > 0) {
|
||||
fsync(pHelper->files.headF.fd);
|
||||
close(pHelper->files.headF.fd);
|
||||
pHelper->files.headF.fd = -1;
|
||||
}
|
||||
if (pHelper->files.dataF.fd > 0) {
|
||||
if (!hasError) tsdbUpdateFileHeader(&(pHelper->files.dataF), 0);
|
||||
fsync(pHelper->files.dataF.fd);
|
||||
close(pHelper->files.dataF.fd);
|
||||
pHelper->files.dataF.fd = -1;
|
||||
}
|
||||
if (pHelper->files.lastF.fd > 0) {
|
||||
fsync(pHelper->files.lastF.fd);
|
||||
close(pHelper->files.lastF.fd);
|
||||
pHelper->files.lastF.fd = -1;
|
||||
}
|
||||
if (pHelper->files.nHeadF.fd > 0) {
|
||||
if (!hasError) tsdbUpdateFileHeader(&(pHelper->files.nHeadF), 0);
|
||||
fsync(pHelper->files.nHeadF.fd);
|
||||
close(pHelper->files.nHeadF.fd);
|
||||
pHelper->files.nHeadF.fd = -1;
|
||||
if (hasError) {
|
||||
|
@ -263,6 +267,7 @@ int tsdbCloseHelperFile(SRWHelper *pHelper, bool hasError) {
|
|||
|
||||
if (pHelper->files.nLastF.fd > 0) {
|
||||
if (!hasError) tsdbUpdateFileHeader(&(pHelper->files.nLastF), 0);
|
||||
fsync(pHelper->files.nLastF.fd);
|
||||
close(pHelper->files.nLastF.fd);
|
||||
pHelper->files.nLastF.fd = -1;
|
||||
if (hasError) {
|
||||
|
@ -443,7 +448,12 @@ int tsdbWriteCompIdx(SRWHelper *pHelper) {
|
|||
for (uint32_t i = 0; i < pHelper->config.maxTables; i++) {
|
||||
SCompIdx *pCompIdx = pHelper->pCompIdx + i;
|
||||
if (pCompIdx->offset > 0) {
|
||||
buf = taosEncodeVariant32(buf, i);
|
||||
int drift = POINTER_DISTANCE(buf, pHelper->pBuffer);
|
||||
if (tsizeof(pHelper->pBuffer) - drift < 128) {
|
||||
pHelper->pBuffer = trealloc(pHelper->pBuffer, tsizeof(pHelper->pBuffer)*2);
|
||||
}
|
||||
buf = POINTER_SHIFT(pHelper->pBuffer, drift);
|
||||
buf = taosEncodeVariantU32(buf, i);
|
||||
buf = tsdbEncodeSCompIdx(buf, pCompIdx);
|
||||
}
|
||||
}
|
||||
|
@ -469,6 +479,7 @@ int tsdbLoadCompIdx(SRWHelper *pHelper, void *target) {
|
|||
ASSERT(pFile->info.offset > TSDB_FILE_HEAD_SIZE);
|
||||
|
||||
if (lseek(fd, pFile->info.offset, SEEK_SET) < 0) return -1;
|
||||
if ((pHelper->pBuffer = trealloc(pHelper->pBuffer, pFile->info.len)) == NULL) return -1;
|
||||
if (tread(fd, (void *)(pHelper->pBuffer), pFile->info.len) < pFile->info.len)
|
||||
return -1;
|
||||
if (!taosCheckChecksumWhole((uint8_t *)(pHelper->pBuffer), pFile->info.len)) {
|
||||
|
@ -480,7 +491,7 @@ int tsdbLoadCompIdx(SRWHelper *pHelper, void *target) {
|
|||
void *ptr = pHelper->pBuffer;
|
||||
while (((char *)ptr - (char *)pHelper->pBuffer) < (pFile->info.len - sizeof(TSCKSUM))) {
|
||||
uint32_t tid = 0;
|
||||
if ((ptr = taosDecodeVariant32(ptr, &tid)) == NULL) return -1;
|
||||
if ((ptr = taosDecodeVariantU32(ptr, &tid)) == NULL) return -1;
|
||||
ASSERT(tid > 0 && tid < pHelper->config.maxTables);
|
||||
|
||||
if ((ptr = tsdbDecodeSCompIdx(ptr, pHelper->pCompIdx + tid)) == NULL) return -1;
|
||||
|
@ -1242,12 +1253,12 @@ static int tsdbGetRowsInRange(SDataCols *pDataCols, TSKEY minKey, TSKEY maxKey)
|
|||
}
|
||||
|
||||
void *tsdbEncodeSCompIdx(void *buf, SCompIdx *pIdx) {
|
||||
buf = taosEncodeVariant32(buf, pIdx->len);
|
||||
buf = taosEncodeVariant32(buf, pIdx->offset);
|
||||
buf = taosEncodeFixed8(buf, pIdx->hasLast);
|
||||
buf = taosEncodeVariant32(buf, pIdx->numOfBlocks);
|
||||
buf = taosEncodeFixed64(buf, pIdx->uid);
|
||||
buf = taosEncodeFixed64(buf, pIdx->maxKey);
|
||||
buf = taosEncodeVariantU32(buf, pIdx->len);
|
||||
buf = taosEncodeVariantU32(buf, pIdx->offset);
|
||||
buf = taosEncodeFixedU8(buf, pIdx->hasLast);
|
||||
buf = taosEncodeVariantU32(buf, pIdx->numOfBlocks);
|
||||
buf = taosEncodeFixedU64(buf, pIdx->uid);
|
||||
buf = taosEncodeFixedU64(buf, pIdx->maxKey);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
@ -1257,15 +1268,15 @@ void *tsdbDecodeSCompIdx(void *buf, SCompIdx *pIdx) {
|
|||
uint32_t numOfBlocks = 0;
|
||||
uint64_t value = 0;
|
||||
|
||||
if ((buf = taosDecodeVariant32(buf, &(pIdx->len))) == NULL) return NULL;
|
||||
if ((buf = taosDecodeVariant32(buf, &(pIdx->offset))) == NULL) return NULL;
|
||||
if ((buf = taosDecodeFixed8(buf, &(hasLast))) == NULL) return NULL;
|
||||
if ((buf = taosDecodeVariantU32(buf, &(pIdx->len))) == NULL) return NULL;
|
||||
if ((buf = taosDecodeVariantU32(buf, &(pIdx->offset))) == NULL) return NULL;
|
||||
if ((buf = taosDecodeFixedU8(buf, &(hasLast))) == NULL) return NULL;
|
||||
pIdx->hasLast = hasLast;
|
||||
if ((buf = taosDecodeVariant32(buf, &(numOfBlocks))) == NULL) return NULL;
|
||||
if ((buf = taosDecodeVariantU32(buf, &(numOfBlocks))) == NULL) return NULL;
|
||||
pIdx->numOfBlocks = numOfBlocks;
|
||||
if ((buf = taosDecodeFixed64(buf, &value)) == NULL) return NULL;
|
||||
if ((buf = taosDecodeFixedU64(buf, &value)) == NULL) return NULL;
|
||||
pIdx->uid = (int64_t)value;
|
||||
if ((buf = taosDecodeFixed64(buf, &value)) == NULL) return NULL;
|
||||
if ((buf = taosDecodeFixedU64(buf, &value)) == NULL) return NULL;
|
||||
pIdx->maxKey = (TSKEY)value;
|
||||
|
||||
return buf;
|
||||
|
@ -1275,7 +1286,7 @@ int tsdbUpdateFileHeader(SFile *pFile, uint32_t version) {
|
|||
char buf[TSDB_FILE_HEAD_SIZE] = "\0";
|
||||
|
||||
void *pBuf = (void *)buf;
|
||||
pBuf = taosEncodeFixed32(pBuf, version);
|
||||
pBuf = taosEncodeFixedU32(pBuf, version);
|
||||
pBuf = tsdbEncodeSFileInfo(pBuf, &(pFile->info));
|
||||
|
||||
taosCalcChecksumAppend(0, (uint8_t *)buf, TSDB_FILE_HEAD_SIZE);
|
||||
|
@ -1289,23 +1300,23 @@ int tsdbUpdateFileHeader(SFile *pFile, uint32_t version) {
|
|||
|
||||
|
||||
void *tsdbEncodeSFileInfo(void *buf, const STsdbFileInfo *pInfo) {
|
||||
buf = taosEncodeFixed32(buf, pInfo->offset);
|
||||
buf = taosEncodeFixed32(buf, pInfo->len);
|
||||
buf = taosEncodeFixed64(buf, pInfo->size);
|
||||
buf = taosEncodeFixed64(buf, pInfo->tombSize);
|
||||
buf = taosEncodeFixed32(buf, pInfo->totalBlocks);
|
||||
buf = taosEncodeFixed32(buf, pInfo->totalSubBlocks);
|
||||
buf = taosEncodeFixedU32(buf, pInfo->offset);
|
||||
buf = taosEncodeFixedU32(buf, pInfo->len);
|
||||
buf = taosEncodeFixedU64(buf, pInfo->size);
|
||||
buf = taosEncodeFixedU64(buf, pInfo->tombSize);
|
||||
buf = taosEncodeFixedU32(buf, pInfo->totalBlocks);
|
||||
buf = taosEncodeFixedU32(buf, pInfo->totalSubBlocks);
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
void *tsdbDecodeSFileInfo(void *buf, STsdbFileInfo *pInfo) {
|
||||
buf = taosDecodeFixed32(buf, &(pInfo->offset));
|
||||
buf = taosDecodeFixed32(buf, &(pInfo->len));
|
||||
buf = taosDecodeFixed64(buf, &(pInfo->size));
|
||||
buf = taosDecodeFixed64(buf, &(pInfo->tombSize));
|
||||
buf = taosDecodeFixed32(buf, &(pInfo->totalBlocks));
|
||||
buf = taosDecodeFixed32(buf, &(pInfo->totalSubBlocks));
|
||||
buf = taosDecodeFixedU32(buf, &(pInfo->offset));
|
||||
buf = taosDecodeFixedU32(buf, &(pInfo->len));
|
||||
buf = taosDecodeFixedU64(buf, &(pInfo->size));
|
||||
buf = taosDecodeFixedU64(buf, &(pInfo->tombSize));
|
||||
buf = taosDecodeFixedU32(buf, &(pInfo->totalBlocks));
|
||||
buf = taosDecodeFixedU32(buf, &(pInfo->totalSubBlocks));
|
||||
|
||||
return buf;
|
||||
}
|
|
@ -95,7 +95,6 @@ typedef struct STsdbQueryHandle {
|
|||
SQueryFilePos cur; // current position
|
||||
int16_t order;
|
||||
STimeWindow window; // the primary query time window that applies to all queries
|
||||
SCompBlock* pBlock;
|
||||
SDataStatis* statis; // query level statistics, only one table block statistics info exists at any time
|
||||
int32_t numOfBlocks;
|
||||
SArray* pColumns; // column list, SColumnInfoData array list
|
||||
|
@ -117,6 +116,12 @@ typedef struct STsdbQueryHandle {
|
|||
} STsdbQueryHandle;
|
||||
|
||||
static void changeQueryHandleForLastrowQuery(TsdbQueryHandleT pqHandle);
|
||||
static void changeQueryHandleForInterpQuery(TsdbQueryHandleT pHandle);
|
||||
static void doMergeTwoLevelData(STsdbQueryHandle* pQueryHandle, STableCheckInfo* pCheckInfo, SCompBlock* pBlock,
|
||||
SArray* sa);
|
||||
static int32_t binarySearchForKey(char* pValue, int num, TSKEY key, int order);
|
||||
static int tsdbReadRowsFromCache(SSkipListIterator* pIter, STable* pTable, TSKEY maxKey, int maxRowsToRead, TSKEY* skey, TSKEY* ekey,
|
||||
STsdbQueryHandle* pQueryHandle);
|
||||
|
||||
static void tsdbInitDataBlockLoadInfo(SDataBlockLoadInfo* pBlockLoadInfo) {
|
||||
pBlockLoadInfo->slot = -1;
|
||||
|
@ -188,9 +193,6 @@ TsdbQueryHandleT* tsdbQueryTables(TsdbRepoT* tsdb, STsdbQueryCond* pCond, STable
|
|||
}
|
||||
}
|
||||
|
||||
for(int32_t i = 0; i < numOfCols; ++i) {
|
||||
}
|
||||
|
||||
uTrace("%p total numOfTable:%d in query", pQueryHandle, taosArrayGetSize(pQueryHandle->pTableCheckInfo));
|
||||
|
||||
tsdbInitDataBlockLoadInfo(&pQueryHandle->dataBlockLoadInfo);
|
||||
|
@ -209,13 +211,29 @@ TsdbQueryHandleT tsdbQueryLastRow(TsdbRepoT *tsdb, STsdbQueryCond *pCond, STable
|
|||
return pQueryHandle;
|
||||
}
|
||||
|
||||
SArray* tsdbGetQueriedTableIdList(TsdbQueryHandleT *pHandle) {
|
||||
assert(pHandle != NULL);
|
||||
|
||||
STsdbQueryHandle *pQueryHandle = (STsdbQueryHandle*) pHandle;
|
||||
|
||||
size_t size = taosArrayGetSize(pQueryHandle->pTableCheckInfo);
|
||||
SArray* res = taosArrayInit(size, sizeof(STableId));
|
||||
|
||||
for(int32_t i = 0; i < size; ++i) {
|
||||
STableCheckInfo* pCheckInfo = taosArrayGet(pQueryHandle->pTableCheckInfo, i);
|
||||
taosArrayPush(res, &pCheckInfo->tableId);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
TsdbQueryHandleT tsdbQueryRowsInExternalWindow(TsdbRepoT *tsdb, STsdbQueryCond* pCond, STableGroupInfo *groupList) {
|
||||
STsdbQueryHandle *pQueryHandle = (STsdbQueryHandle*) tsdbQueryTables(tsdb, pCond, groupList);
|
||||
|
||||
pQueryHandle->type = TSDB_QUERY_TYPE_EXTERNAL;
|
||||
pQueryHandle->order = TSDB_ORDER_ASC;
|
||||
// pQueryHandle->outputCapacity = 2; // only allowed two rows to be loaded
|
||||
|
||||
// changeQueryHandleForLastrowQuery(pQueryHandle);
|
||||
changeQueryHandleForInterpQuery(pQueryHandle);
|
||||
return pQueryHandle;
|
||||
}
|
||||
|
||||
|
@ -328,13 +346,36 @@ static bool hasMoreDataInCache(STsdbQueryHandle* pHandle) {
|
|||
(pCheckInfo->lastKey < pHandle->window.ekey && !ASCENDING_TRAVERSE(pHandle->order))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int32_t step = ASCENDING_TRAVERSE(pHandle->order)? 1:-1;
|
||||
STimeWindow* win = &pHandle->cur.win;
|
||||
pHandle->cur.rows = tsdbReadRowsFromCache(pCheckInfo->iter, pCheckInfo->pTableObj, pHandle->window.ekey,
|
||||
pHandle->outputCapacity, &win->skey, &win->ekey, pHandle); // todo refactor API
|
||||
|
||||
// update the last key value
|
||||
pCheckInfo->lastKey = win->ekey + step;
|
||||
pHandle->cur.lastKey = win->ekey + step;
|
||||
pHandle->cur.mixBlock = true;
|
||||
|
||||
if (!ASCENDING_TRAVERSE(pHandle->order)) {
|
||||
SWAP(win->skey, win->ekey, TSKEY);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int32_t getFileIdFromKey(TSKEY key, int32_t daysPerFile) {
|
||||
int64_t fid = (int64_t)(key / (daysPerFile * tsMsPerDay[0])); // set the starting fileId
|
||||
if (fid > INT32_MAX) {
|
||||
static int32_t getFileIdFromKey(TSKEY key, int32_t daysPerFile, int32_t precision) {
|
||||
assert(precision >= TSDB_TIME_PRECISION_MICRO || precision <= TSDB_TIME_PRECISION_NANO);
|
||||
if (key == TSKEY_INITIAL_VAL) {
|
||||
return INT32_MIN;
|
||||
}
|
||||
|
||||
int64_t fid = (int64_t)(key / (daysPerFile * tsMsPerDay[precision])); // set the starting fileId
|
||||
if (fid < 0L && llabs(fid) > INT32_MAX) { // data value overflow for INT32
|
||||
fid = INT32_MIN;
|
||||
}
|
||||
|
||||
if (fid > 0L && fid > INT32_MAX) {
|
||||
fid = INT32_MAX;
|
||||
}
|
||||
|
||||
|
@ -472,12 +513,6 @@ static SArray* getDefaultLoadColumns(STsdbQueryHandle* pQueryHandle, bool loadTS
|
|||
return pLocalIdList;
|
||||
}
|
||||
|
||||
static void doMergeTwoLevelData(STsdbQueryHandle* pQueryHandle, STableCheckInfo* pCheckInfo, SCompBlock* pBlock,
|
||||
SArray* sa);
|
||||
static int32_t binarySearchForKey(char* pValue, int num, TSKEY key, int order);
|
||||
static int tsdbReadRowsFromCache(SSkipListIterator* pIter, STable* pTable, TSKEY maxKey, int maxRowsToRead, TSKEY* skey, TSKEY* ekey,
|
||||
STsdbQueryHandle* pQueryHandle);
|
||||
|
||||
static bool doLoadFileDataBlock(STsdbQueryHandle* pQueryHandle, SCompBlock* pBlock, STableCheckInfo* pCheckInfo) {
|
||||
STsdbRepo *pRepo = pQueryHandle->pTsdb;
|
||||
SCompData* data = calloc(1, sizeof(SCompData) + sizeof(SCompCol) * pBlock->numOfCols);
|
||||
|
@ -581,13 +616,21 @@ static void handleDataMergeIfNeeded(STsdbQueryHandle* pQueryHandle, SCompBlock*
|
|||
}
|
||||
|
||||
SArray* sa = getDefaultLoadColumns(pQueryHandle, true);
|
||||
|
||||
doLoadFileDataBlock(pQueryHandle, pBlock, pCheckInfo);
|
||||
doMergeTwoLevelData(pQueryHandle, pCheckInfo, pBlock, sa);
|
||||
taosArrayDestroy(sa);
|
||||
|
||||
} else {
|
||||
/*
|
||||
* no data in cache, only load data from file
|
||||
* during the query processing, data in cache will not be checked anymore.
|
||||
*
|
||||
* Here the buffer is not enough, so only part of file block can be loaded into memory buffer
|
||||
*/
|
||||
assert(pQueryHandle->outputCapacity >= binfo.rows);
|
||||
pQueryHandle->realNumOfRows = binfo.rows;
|
||||
|
||||
|
||||
cur->rows = binfo.rows;
|
||||
cur->win = binfo.window;
|
||||
cur->mixBlock = false;
|
||||
|
@ -622,15 +665,14 @@ static bool loadFileDataBlock(STsdbQueryHandle* pQueryHandle, SCompBlock* pBlock
|
|||
handleDataMergeIfNeeded(pQueryHandle, pBlock, pCheckInfo);
|
||||
}
|
||||
} else { //desc order, query ended in current block
|
||||
if (pQueryHandle->window.ekey > pBlock->keyFirst) {
|
||||
if (pQueryHandle->window.ekey > pBlock->keyFirst || pCheckInfo->lastKey < pBlock->keyLast) {
|
||||
if (!doLoadFileDataBlock(pQueryHandle, pBlock, pCheckInfo)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SDataCols* pDataCols = pCheckInfo->pDataCols;
|
||||
|
||||
SDataCols* pTSCol = pQueryHandle->rhelper.pDataCols[0];
|
||||
if (pCheckInfo->lastKey < pBlock->keyLast) {
|
||||
cur->pos =
|
||||
binarySearchForKey(pDataCols->cols[0].pData, pBlock->numOfRows, pCheckInfo->lastKey, pQueryHandle->order);
|
||||
cur->pos = binarySearchForKey(pTSCol->cols[0].pData, pBlock->numOfRows, pCheckInfo->lastKey, pQueryHandle->order);
|
||||
} else {
|
||||
cur->pos = pBlock->numOfRows - 1;
|
||||
}
|
||||
|
@ -1011,7 +1053,7 @@ int32_t binarySearchForKey(char* pValue, int num, TSKEY key, int order) {
|
|||
firstPos = 0;
|
||||
lastPos = num - 1;
|
||||
|
||||
if (order == 0) {
|
||||
if (order == TSDB_ORDER_DESC) {
|
||||
// find the first position which is smaller than the key
|
||||
while (1) {
|
||||
if (key >= keyList[lastPos]) return lastPos;
|
||||
|
@ -1256,7 +1298,8 @@ static bool getDataBlocksInFiles(STsdbQueryHandle* pQueryHandle) {
|
|||
// find the start data block in file
|
||||
if (!pQueryHandle->locateStart) {
|
||||
pQueryHandle->locateStart = true;
|
||||
int32_t fid = getFileIdFromKey(pQueryHandle->window.skey, pQueryHandle->pTsdb->config.daysPerFile);
|
||||
STsdbCfg* pCfg = &pQueryHandle->pTsdb->config;
|
||||
int32_t fid = getFileIdFromKey(pQueryHandle->window.skey, pCfg->daysPerFile, pCfg->precision);
|
||||
|
||||
tsdbInitFileGroupIter(pFileHandle, &pQueryHandle->fileIter, pQueryHandle->order);
|
||||
tsdbSeekFileGroupIter(&pQueryHandle->fileIter, fid);
|
||||
|
@ -1293,7 +1336,7 @@ static bool getDataBlocksInFiles(STsdbQueryHandle* pQueryHandle) {
|
|||
|
||||
static bool doHasDataInBuffer(STsdbQueryHandle* pQueryHandle) {
|
||||
size_t numOfTables = taosArrayGetSize(pQueryHandle->pTableCheckInfo);
|
||||
// todo add assert, the value of numOfTables should be less than the maximum value for each vnode capacity
|
||||
assert(numOfTables <= ((STsdbRepo*)pQueryHandle->pTsdb)->config.maxTables);
|
||||
|
||||
while (pQueryHandle->activeIndex < numOfTables) {
|
||||
if (hasMoreDataInCache(pQueryHandle)) {
|
||||
|
@ -1307,12 +1350,116 @@ static bool doHasDataInBuffer(STsdbQueryHandle* pQueryHandle) {
|
|||
}
|
||||
|
||||
// handle data in cache situation
|
||||
bool tsdbNextDataBlock(TsdbQueryHandleT* pqHandle) {
|
||||
STsdbQueryHandle* pQueryHandle = (STsdbQueryHandle*) pqHandle;
|
||||
bool tsdbNextDataBlock(TsdbQueryHandleT* pHandle) {
|
||||
STsdbQueryHandle* pQueryHandle = (STsdbQueryHandle*) pHandle;
|
||||
|
||||
size_t numOfTables = taosArrayGetSize(pQueryHandle->pTableCheckInfo);
|
||||
assert(numOfTables > 0);
|
||||
|
||||
if (pQueryHandle->type == TSDB_QUERY_TYPE_EXTERNAL) {
|
||||
pQueryHandle->type = TSDB_QUERY_TYPE_ALL;
|
||||
pQueryHandle->order = TSDB_ORDER_DESC;
|
||||
|
||||
if (!tsdbNextDataBlock(pHandle)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SArray* sa = getDefaultLoadColumns(pQueryHandle, true);
|
||||
/*SDataBlockInfo* pBlockInfo =*/ tsdbRetrieveDataBlockInfo(pHandle);
|
||||
/*SArray *pDataBlock = */tsdbRetrieveDataBlock(pHandle, sa);
|
||||
|
||||
if (pQueryHandle->cur.win.ekey == pQueryHandle->window.skey) {
|
||||
// data already retrieve, discard other data rows and return
|
||||
int32_t numOfCols = QH_GET_NUM_OF_COLS(pQueryHandle);
|
||||
for (int32_t i = 0; i < numOfCols; ++i) {
|
||||
SColumnInfoData* pCol = taosArrayGet(pQueryHandle->pColumns, i);
|
||||
memcpy(pCol->pData, pCol->pData + pCol->info.bytes * (pQueryHandle->cur.rows-1), pCol->info.bytes);
|
||||
}
|
||||
|
||||
pQueryHandle->cur.win = (STimeWindow){pQueryHandle->window.skey, pQueryHandle->window.skey};
|
||||
pQueryHandle->window = pQueryHandle->cur.win;
|
||||
pQueryHandle->cur.rows = 1;
|
||||
pQueryHandle->type = TSDB_QUERY_TYPE_EXTERNAL;
|
||||
return true;
|
||||
} else {
|
||||
STsdbQueryHandle* pSecQueryHandle = calloc(1, sizeof(STsdbQueryHandle));
|
||||
pSecQueryHandle->order = TSDB_ORDER_ASC;
|
||||
pSecQueryHandle->window = (STimeWindow) {pQueryHandle->window.skey, INT64_MAX};
|
||||
pSecQueryHandle->pTsdb = pQueryHandle->pTsdb;
|
||||
pSecQueryHandle->type = TSDB_QUERY_TYPE_ALL;
|
||||
pSecQueryHandle->cur.fid = -1;
|
||||
pSecQueryHandle->cur.win = TSWINDOW_INITIALIZER;
|
||||
pSecQueryHandle->checkFiles = true;
|
||||
pSecQueryHandle->activeIndex = 0;
|
||||
pSecQueryHandle->outputCapacity = ((STsdbRepo*)pSecQueryHandle->pTsdb)->config.maxRowsPerFileBlock;
|
||||
|
||||
tsdbInitReadHelper(&pSecQueryHandle->rhelper, (STsdbRepo*) pSecQueryHandle->pTsdb);
|
||||
|
||||
// allocate buffer in order to load data blocks from file
|
||||
int32_t numOfCols = QH_GET_NUM_OF_COLS(pQueryHandle);
|
||||
|
||||
pSecQueryHandle->statis = calloc(numOfCols, sizeof(SDataStatis));
|
||||
pSecQueryHandle->pColumns = taosArrayInit(numOfCols, sizeof(SColumnInfoData));
|
||||
|
||||
for (int32_t i = 0; i < numOfCols; ++i) {
|
||||
SColumnInfoData colInfo = {{0}, 0};
|
||||
SColumnInfoData* pCol = taosArrayGet(pQueryHandle->pColumns, i);
|
||||
|
||||
colInfo.info = pCol->info;
|
||||
colInfo.pData = calloc(1, EXTRA_BYTES + pQueryHandle->outputCapacity * pCol->info.bytes);
|
||||
taosArrayPush(pSecQueryHandle->pColumns, &colInfo);
|
||||
pSecQueryHandle->statis[i].colId = colInfo.info.colId;
|
||||
}
|
||||
|
||||
size_t si = taosArrayGetSize(pQueryHandle->pTableCheckInfo);
|
||||
pSecQueryHandle->pTableCheckInfo = taosArrayInit(si, sizeof(STableCheckInfo));
|
||||
STsdbMeta* pMeta = tsdbGetMeta(pQueryHandle->pTsdb);
|
||||
assert(pMeta != NULL);
|
||||
|
||||
for (int32_t j = 0; j < si; ++j) {
|
||||
STableCheckInfo* pCheckInfo = (STableCheckInfo*) taosArrayGet(pQueryHandle->pTableCheckInfo, j);
|
||||
|
||||
STableCheckInfo info = {
|
||||
.lastKey = pSecQueryHandle->window.skey,
|
||||
.tableId = pCheckInfo->tableId,
|
||||
.pTableObj = pCheckInfo->pTableObj,
|
||||
};
|
||||
|
||||
taosArrayPush(pSecQueryHandle->pTableCheckInfo, &info);
|
||||
}
|
||||
|
||||
tsdbInitDataBlockLoadInfo(&pSecQueryHandle->dataBlockLoadInfo);
|
||||
tsdbInitCompBlockLoadInfo(&pSecQueryHandle->compBlockLoadInfo);
|
||||
|
||||
bool ret = tsdbNextDataBlock((void*) pSecQueryHandle);
|
||||
assert(ret);
|
||||
|
||||
/*SDataBlockInfo* pBlockInfo =*/ tsdbRetrieveDataBlockInfo((void*) pSecQueryHandle);
|
||||
/*SArray *pDataBlock = */tsdbRetrieveDataBlock((void*) pSecQueryHandle, sa);
|
||||
|
||||
for (int32_t i = 0; i < numOfCols; ++i) {
|
||||
SColumnInfoData* pCol = taosArrayGet(pQueryHandle->pColumns, i);
|
||||
memcpy(pCol->pData, pCol->pData + pCol->info.bytes * (pQueryHandle->cur.rows-1), pCol->info.bytes);
|
||||
|
||||
SColumnInfoData* pCol1 = taosArrayGet(pSecQueryHandle->pColumns, i);
|
||||
assert(pCol->info.colId == pCol1->info.colId);
|
||||
|
||||
memcpy(pCol->pData + pCol->info.bytes, pCol1->pData, pCol1->info.bytes);
|
||||
}
|
||||
|
||||
SColumnInfoData* pTSCol = taosArrayGet(pQueryHandle->pColumns, 0);
|
||||
|
||||
pQueryHandle->cur.win = (STimeWindow){((TSKEY*)pTSCol->pData)[0], ((TSKEY*)pTSCol->pData)[1]};
|
||||
pQueryHandle->window = pQueryHandle->cur.win;
|
||||
pQueryHandle->cur.rows = 2;
|
||||
|
||||
tsdbCleanupQueryHandle(pSecQueryHandle);
|
||||
}
|
||||
|
||||
pQueryHandle->type = TSDB_QUERY_TYPE_EXTERNAL;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (pQueryHandle->checkFiles) {
|
||||
if (getDataBlocksInFiles(pQueryHandle)) {
|
||||
return true;
|
||||
|
@ -1322,7 +1469,6 @@ bool tsdbNextDataBlock(TsdbQueryHandleT* pqHandle) {
|
|||
pQueryHandle->checkFiles = false;
|
||||
}
|
||||
|
||||
// TODO: opt by using lastKeyOnFile
|
||||
// TODO: opt by consider the scan order
|
||||
return doHasDataInBuffer(pQueryHandle);
|
||||
}
|
||||
|
@ -1336,23 +1482,25 @@ void changeQueryHandleForLastrowQuery(TsdbQueryHandleT pqHandle) {
|
|||
// todo consider the query time window, current last_row does not apply the query time window
|
||||
size_t numOfTables = taosArrayGetSize(pQueryHandle->pTableCheckInfo);
|
||||
|
||||
TSKEY key = 0;
|
||||
TSKEY key = TSKEY_INITIAL_VAL;
|
||||
int32_t index = -1;
|
||||
|
||||
for(int32_t i = 0; i < numOfTables; ++i) {
|
||||
STableCheckInfo* pCheckInfo = taosArrayGet(pQueryHandle->pTableCheckInfo, i);
|
||||
if (pCheckInfo->pTableObj->lastKey > key) { //todo lastKey should not be 0 by default
|
||||
if (pCheckInfo->pTableObj->tableId.uid == 12094628167747) {
|
||||
printf("abc\n");
|
||||
}
|
||||
if (pCheckInfo->pTableObj->lastKey > key) {
|
||||
key = pCheckInfo->pTableObj->lastKey;
|
||||
index = i;
|
||||
}
|
||||
}
|
||||
|
||||
// todo, there are no data in all the tables. opt performance
|
||||
if (index == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
// erase all other elements in array list, todo refactor
|
||||
// erase all other elements in array list
|
||||
size_t size = taosArrayGetSize(pQueryHandle->pTableCheckInfo);
|
||||
for (int32_t i = 0; i < size; ++i) {
|
||||
if (i == index) {
|
||||
|
@ -1371,9 +1519,7 @@ void changeQueryHandleForLastrowQuery(TsdbQueryHandleT pqHandle) {
|
|||
}
|
||||
|
||||
STableCheckInfo info = *(STableCheckInfo*) taosArrayGet(pQueryHandle->pTableCheckInfo, index);
|
||||
taosArrayDestroy(pQueryHandle->pTableCheckInfo);
|
||||
|
||||
pQueryHandle->pTableCheckInfo = taosArrayInit(1, sizeof(STableCheckInfo));
|
||||
taosArrayClear(pQueryHandle->pTableCheckInfo);
|
||||
|
||||
info.lastKey = key;
|
||||
taosArrayPush(pQueryHandle->pTableCheckInfo, &info);
|
||||
|
@ -1382,6 +1528,43 @@ void changeQueryHandleForLastrowQuery(TsdbQueryHandleT pqHandle) {
|
|||
pQueryHandle->window = (STimeWindow) {key, key};
|
||||
}
|
||||
|
||||
static void changeQueryHandleForInterpQuery(TsdbQueryHandleT pHandle) {
|
||||
// filter the queried time stamp in the first place
|
||||
STsdbQueryHandle* pQueryHandle = (STsdbQueryHandle*) pHandle;
|
||||
pQueryHandle->order = TSDB_ORDER_DESC;
|
||||
|
||||
assert(pQueryHandle->window.skey == pQueryHandle->window.ekey);
|
||||
|
||||
// starts from the buffer in case of descending timestamp order check data blocks
|
||||
// todo consider the query time window, current last_row does not apply the query time window
|
||||
size_t numOfTables = taosArrayGetSize(pQueryHandle->pTableCheckInfo);
|
||||
|
||||
int32_t i = 0;
|
||||
while(i < numOfTables) {
|
||||
STableCheckInfo* pCheckInfo = taosArrayGet(pQueryHandle->pTableCheckInfo, i);
|
||||
if (pQueryHandle->window.skey <= pCheckInfo->pTableObj->lastKey &&
|
||||
pCheckInfo->pTableObj->lastKey != TSKEY_INITIAL_VAL) {
|
||||
break;
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
// there are no data in all the tables
|
||||
if (i == numOfTables) {
|
||||
return;
|
||||
}
|
||||
|
||||
STableCheckInfo info = *(STableCheckInfo*) taosArrayGet(pQueryHandle->pTableCheckInfo, i);
|
||||
taosArrayClear(pQueryHandle->pTableCheckInfo);
|
||||
|
||||
info.lastKey = pQueryHandle->window.skey;
|
||||
taosArrayPush(pQueryHandle->pTableCheckInfo, &info);
|
||||
|
||||
// update the query time window according to the chosen last timestamp
|
||||
pQueryHandle->window = (STimeWindow) {info.lastKey, TSKEY_INITIAL_VAL};
|
||||
}
|
||||
|
||||
static int tsdbReadRowsFromCache(SSkipListIterator* pIter, STable* pTable, TSKEY maxKey, int maxRowsToRead, TSKEY* skey, TSKEY* ekey,
|
||||
STsdbQueryHandle* pQueryHandle) {
|
||||
int numOfRows = 0;
|
||||
|
@ -1466,58 +1649,29 @@ static int tsdbReadRowsFromCache(SSkipListIterator* pIter, STable* pTable, TSKEY
|
|||
return numOfRows;
|
||||
}
|
||||
|
||||
// copy data from cache into data block
|
||||
SDataBlockInfo tsdbRetrieveDataBlockInfo(TsdbQueryHandleT* pQueryHandle) {
|
||||
STsdbQueryHandle* pHandle = (STsdbQueryHandle*)pQueryHandle;
|
||||
|
||||
int32_t step = ASCENDING_TRAVERSE(pHandle->order)? 1:-1;
|
||||
SQueryFilePos* cur = &pHandle->cur;
|
||||
STable* pTable = NULL;
|
||||
|
||||
// there are data in file
|
||||
if (pHandle->cur.fid >= 0) {
|
||||
STableBlockInfo* pBlockInfo = &pHandle->pDataBlockInfo[pHandle->cur.slot];
|
||||
STable* pTable = pBlockInfo->pTableCheckInfo->pTableObj;
|
||||
|
||||
SDataBlockInfo blockInfo = {
|
||||
.uid = pTable->tableId.uid,
|
||||
.tid = pTable->tableId.tid,
|
||||
.rows = pHandle->cur.rows,
|
||||
.window = pHandle->cur.win,
|
||||
.numOfCols = QH_GET_NUM_OF_COLS(pHandle),
|
||||
};
|
||||
|
||||
return blockInfo;
|
||||
STableBlockInfo* pBlockInfo = &pHandle->pDataBlockInfo[cur->slot];
|
||||
pTable = pBlockInfo->pTableCheckInfo->pTableObj;
|
||||
} else {
|
||||
STableCheckInfo* pCheckInfo = taosArrayGet(pHandle->pTableCheckInfo, pHandle->activeIndex);
|
||||
SQueryFilePos* cur = &pHandle->cur;
|
||||
|
||||
STable* pTable = pCheckInfo->pTableObj;
|
||||
if (pTable->mem != NULL) { // create mem table iterator if it is not created yet
|
||||
assert(pCheckInfo->iter != NULL);
|
||||
STimeWindow* win = &cur->win;
|
||||
|
||||
pHandle->cur.rows = tsdbReadRowsFromCache(pCheckInfo->iter, pCheckInfo->pTableObj, pHandle->window.ekey,
|
||||
pHandle->outputCapacity, &win->skey, &win->ekey, pHandle); // todo refactor API
|
||||
|
||||
// update the last key value
|
||||
pCheckInfo->lastKey = win->ekey + step;
|
||||
cur->lastKey = win->ekey + step;
|
||||
cur->mixBlock = true;
|
||||
}
|
||||
|
||||
if (!ASCENDING_TRAVERSE(pHandle->order)) {
|
||||
SWAP(pHandle->cur.win.skey, pHandle->cur.win.ekey, TSKEY);
|
||||
}
|
||||
|
||||
SDataBlockInfo blockInfo = {
|
||||
.uid = pTable->tableId.uid,
|
||||
.tid = pTable->tableId.tid,
|
||||
.rows = pHandle->cur.rows,
|
||||
.window = pHandle->cur.win,
|
||||
.numOfCols = QH_GET_NUM_OF_COLS(pHandle),
|
||||
};
|
||||
|
||||
return blockInfo;
|
||||
pTable = pCheckInfo->pTableObj;
|
||||
}
|
||||
|
||||
SDataBlockInfo blockInfo = {
|
||||
.uid = pTable->tableId.uid,
|
||||
.tid = pTable->tableId.tid,
|
||||
.rows = cur->rows,
|
||||
.window = cur->win,
|
||||
.numOfCols = QH_GET_NUM_OF_COLS(pHandle),
|
||||
};
|
||||
|
||||
return blockInfo;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1536,6 +1690,13 @@ int32_t tsdbRetrieveDataBlockStatisInfo(TsdbQueryHandleT* pQueryHandle, SDataSta
|
|||
((cur->slot == pHandle->numOfBlocks) && (cur->slot == 0)));
|
||||
|
||||
STableBlockInfo* pBlockInfo = &pHandle->pDataBlockInfo[cur->slot];
|
||||
|
||||
// file block with subblocks has no statistics data
|
||||
if (pBlockInfo->compBlock->numOfSubBlocks > 1) {
|
||||
*pBlockStatis = NULL;
|
||||
return TSDB_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
tsdbLoadCompData(&pHandle->rhelper, pBlockInfo->compBlock, NULL);
|
||||
|
||||
size_t numOfCols = QH_GET_NUM_OF_COLS(pHandle);
|
||||
|
@ -1708,12 +1869,7 @@ void filterPrepare(void* expr, void* param) {
|
|||
pInfo->q = (char*) pCond->arr;
|
||||
} else {
|
||||
pInfo->q = calloc(1, pSchema->bytes);
|
||||
if (pSchema->type == TSDB_DATA_TYPE_BINARY || pSchema->type == TSDB_DATA_TYPE_NCHAR) {
|
||||
tVariantDump(pCond, varDataVal(pInfo->q), pSchema->type);
|
||||
varDataSetLen(pInfo->q, pCond->nLen); // the length may be changed after dump, so assign its value after dump
|
||||
} else {
|
||||
tVariantDump(pCond, pInfo->q, pSchema->type);
|
||||
}
|
||||
tVariantDump(pCond, pInfo->q, pSchema->type, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1753,9 +1909,8 @@ int32_t tableGroupComparFn(const void *p1, const void *p2, const void *param) {
|
|||
STColumn* pCol = schemaColAt(pTableGroupSupp->pTagSchema, colIndex);
|
||||
bytes = pCol->bytes;
|
||||
type = pCol->type;
|
||||
int16_t tgtype1, tgtype2 = 0;
|
||||
f1 = tdQueryTagByID(pTable1->tagVal, pCol->colId, &tgtype1);
|
||||
f2 = tdQueryTagByID(pTable2->tagVal, pCol->colId, &tgtype2);
|
||||
f1 = tdGetKVRowValOfCol(pTable1->tagVal, pCol->colId);
|
||||
f2 = tdGetKVRowValOfCol(pTable2->tagVal, pCol->colId);
|
||||
}
|
||||
|
||||
int32_t ret = doCompare(f1, f2, type, bytes);
|
||||
|
@ -1843,13 +1998,9 @@ bool indexedNodeFilterFp(const void* pNode, void* param) {
|
|||
val = (char*) elem->pTable->name;
|
||||
type = TSDB_DATA_TYPE_BINARY;
|
||||
} else {
|
||||
// STSchema* pTSchema = (STSchema*) pInfo->param; // todo table schema is identical to stable schema??
|
||||
int16_t type;
|
||||
// int32_t offset = pTSchema->columns[pInfo->colIndex].offset;
|
||||
// val = tdGetRowDataOfCol(elem->pTable->tagVal, pInfo->sch.type, TD_DATA_ROW_HEAD_SIZE + offset);
|
||||
val = tdQueryTagByID(elem->pTable->tagVal, pInfo->sch.colId, &type);
|
||||
// ASSERT(pInfo->sch.type == type);
|
||||
val = tdGetKVRowValOfCol(elem->pTable->tagVal, pInfo->sch.colId);
|
||||
}
|
||||
|
||||
//todo :the val is possible to be null, so check it out carefully
|
||||
int32_t ret = 0;
|
||||
if (type == TSDB_DATA_TYPE_BINARY || type == TSDB_DATA_TYPE_NCHAR) {
|
||||
|
|
|
@ -30,24 +30,19 @@ typedef void (*_hash_free_fn_t)(void *param);
|
|||
|
||||
typedef struct SHashNode {
|
||||
char *key;
|
||||
union {
|
||||
// union {
|
||||
struct SHashNode * prev;
|
||||
struct SHashEntry *prev1;
|
||||
};
|
||||
|
||||
// struct SHashEntry *prev1;
|
||||
// };
|
||||
//
|
||||
struct SHashNode *next;
|
||||
uint32_t hashVal; // the hash value of key, if hashVal == HASH_VALUE_IN_TRASH, this node is moved to trash
|
||||
uint32_t keyLen; // length of the key
|
||||
char data[];
|
||||
} SHashNode;
|
||||
|
||||
typedef struct SHashEntry {
|
||||
SHashNode *next;
|
||||
uint32_t num;
|
||||
} SHashEntry;
|
||||
|
||||
typedef struct SHashObj {
|
||||
SHashEntry ** hashList;
|
||||
SHashNode **hashList;
|
||||
size_t capacity; // number of slots
|
||||
size_t size; // number of elements in hash table
|
||||
_hash_fn_t hashFp; // hash function
|
||||
|
|
|
@ -29,12 +29,33 @@ extern "C" {
|
|||
static const int32_t TNUMBER = 1;
|
||||
#define IS_LITTLE_ENDIAN() (*(uint8_t *)(&TNUMBER) != 0)
|
||||
|
||||
static FORCE_INLINE void *taosEncodeFixed8(void *buf, uint8_t value) {
|
||||
#define ZIGZAGE(T, v) ((u##T)((v) >> (sizeof(T) * 8 - 1))) ^ (((u##T)(v)) << 1) // zigzag encode
|
||||
#define ZIGZAGD(T, v) ((v) >> 1) ^ -((T)((v)&1)) // zigzag decode
|
||||
|
||||
// ---- Fixed U8
|
||||
static FORCE_INLINE void *taosEncodeFixedU8(void *buf, uint8_t value) {
|
||||
((uint8_t *)buf)[0] = value;
|
||||
return POINTER_SHIFT(buf, sizeof(value));
|
||||
}
|
||||
|
||||
static FORCE_INLINE void *taosEncodeFixed16(void *buf, uint16_t value) {
|
||||
static FORCE_INLINE void *taosDecodeFixedU8(void *buf, uint8_t *value) {
|
||||
*value = ((uint8_t *)buf)[0];
|
||||
return POINTER_SHIFT(buf, sizeof(*value));
|
||||
}
|
||||
|
||||
// ---- Fixed I8
|
||||
static FORCE_INLINE void *taosEncodeFixedI8(void *buf, int8_t value) {
|
||||
((int8_t *)buf)[0] = value;
|
||||
return POINTER_SHIFT(buf, sizeof(value));
|
||||
}
|
||||
|
||||
static FORCE_INLINE void *taosDecodeFixedI8(void *buf, int8_t *value) {
|
||||
*value = ((int8_t *)buf)[0];
|
||||
return POINTER_SHIFT(buf, sizeof(*value));
|
||||
}
|
||||
|
||||
// ---- Fixed U16
|
||||
static FORCE_INLINE void *taosEncodeFixedU16(void *buf, uint16_t value) {
|
||||
if (IS_LITTLE_ENDIAN()) {
|
||||
memcpy(buf, &value, sizeof(value));
|
||||
} else {
|
||||
|
@ -45,7 +66,31 @@ static FORCE_INLINE void *taosEncodeFixed16(void *buf, uint16_t value) {
|
|||
return POINTER_SHIFT(buf, sizeof(value));
|
||||
}
|
||||
|
||||
static FORCE_INLINE void *taosEncodeFixed32(void *buf, uint32_t value) {
|
||||
static FORCE_INLINE void *taosDecodeFixedU16(void *buf, uint16_t *value) {
|
||||
if (IS_LITTLE_ENDIAN()) {
|
||||
memcpy(value, buf, sizeof(*value));
|
||||
} else {
|
||||
((uint8_t *)value)[1] = ((uint8_t *)buf)[0];
|
||||
((uint8_t *)value)[0] = ((uint8_t *)buf)[1];
|
||||
}
|
||||
|
||||
return POINTER_SHIFT(buf, sizeof(*value));
|
||||
}
|
||||
|
||||
// ---- Fixed I16
|
||||
static FORCE_INLINE void *taosEncodeFixedI16(void *buf, int16_t value) {
|
||||
return taosEncodeFixedU16(buf, ZIGZAGE(int16_t, value));
|
||||
}
|
||||
|
||||
static FORCE_INLINE void *taosDecodeFixedI16(void *buf, int16_t *value) {
|
||||
uint16_t tvalue = 0;
|
||||
void * ret = taosDecodeFixedU16(buf, &tvalue);
|
||||
*value = ZIGZAGD(int16_t, tvalue);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// ---- Fixed U32
|
||||
static FORCE_INLINE void *taosEncodeFixedU32(void *buf, uint32_t value) {
|
||||
if (IS_LITTLE_ENDIAN()) {
|
||||
memcpy(buf, &value, sizeof(value));
|
||||
} else {
|
||||
|
@ -58,7 +103,33 @@ static FORCE_INLINE void *taosEncodeFixed32(void *buf, uint32_t value) {
|
|||
return POINTER_SHIFT(buf, sizeof(value));
|
||||
}
|
||||
|
||||
static FORCE_INLINE void *taosEncodeFixed64(void *buf, uint64_t value) {
|
||||
static FORCE_INLINE void *taosDecodeFixedU32(void *buf, uint32_t *value) {
|
||||
if (IS_LITTLE_ENDIAN()) {
|
||||
memcpy(value, buf, sizeof(*value));
|
||||
} else {
|
||||
((uint8_t *)value)[3] = ((uint8_t *)buf)[0];
|
||||
((uint8_t *)value)[2] = ((uint8_t *)buf)[1];
|
||||
((uint8_t *)value)[1] = ((uint8_t *)buf)[2];
|
||||
((uint8_t *)value)[0] = ((uint8_t *)buf)[3];
|
||||
}
|
||||
|
||||
return POINTER_SHIFT(buf, sizeof(*value));
|
||||
}
|
||||
|
||||
// ---- Fixed I32
|
||||
static FORCE_INLINE void *taosEncodeFixedI32(void *buf, int32_t value) {
|
||||
return taosEncodeFixedU32(buf, ZIGZAGE(int32_t, value));
|
||||
}
|
||||
|
||||
static FORCE_INLINE void *taosDecodeFixedI32(void *buf, int32_t *value) {
|
||||
uint32_t tvalue = 0;
|
||||
void * ret = taosDecodeFixedU32(buf, &tvalue);
|
||||
*value = ZIGZAGD(int32_t, tvalue);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// ---- Fixed U64
|
||||
static FORCE_INLINE void *taosEncodeFixedU64(void *buf, uint64_t value) {
|
||||
if (IS_LITTLE_ENDIAN()) {
|
||||
memcpy(buf, &value, sizeof(value));
|
||||
} else {
|
||||
|
@ -75,36 +146,7 @@ static FORCE_INLINE void *taosEncodeFixed64(void *buf, uint64_t value) {
|
|||
return POINTER_SHIFT(buf, sizeof(value));
|
||||
}
|
||||
|
||||
static FORCE_INLINE void *taosDecodeFixed8(void *buf, uint8_t *value) {
|
||||
*value = ((uint8_t *)buf)[0];
|
||||
return POINTER_SHIFT(buf, sizeof(*value));
|
||||
}
|
||||
|
||||
static FORCE_INLINE void *taosDecodeFixed16(void *buf, uint16_t *value) {
|
||||
if (IS_LITTLE_ENDIAN()) {
|
||||
memcpy(value, buf, sizeof(*value));
|
||||
} else {
|
||||
((uint8_t *)value)[1] = ((uint8_t *)buf)[0];
|
||||
((uint8_t *)value)[0] = ((uint8_t *)buf)[1];
|
||||
}
|
||||
|
||||
return POINTER_SHIFT(buf, sizeof(*value));
|
||||
}
|
||||
|
||||
static FORCE_INLINE void *taosDecodeFixed32(void *buf, uint32_t *value) {
|
||||
if (IS_LITTLE_ENDIAN()) {
|
||||
memcpy(value, buf, sizeof(*value));
|
||||
} else {
|
||||
((uint8_t *)value)[3] = ((uint8_t *)buf)[0];
|
||||
((uint8_t *)value)[2] = ((uint8_t *)buf)[1];
|
||||
((uint8_t *)value)[1] = ((uint8_t *)buf)[2];
|
||||
((uint8_t *)value)[0] = ((uint8_t *)buf)[3];
|
||||
}
|
||||
|
||||
return POINTER_SHIFT(buf, sizeof(*value));
|
||||
}
|
||||
|
||||
static FORCE_INLINE void *taosDecodeFixed64(void *buf, uint64_t *value) {
|
||||
static FORCE_INLINE void *taosDecodeFixedU64(void *buf, uint64_t *value) {
|
||||
if (IS_LITTLE_ENDIAN()) {
|
||||
memcpy(value, buf, sizeof(*value));
|
||||
} else {
|
||||
|
@ -121,7 +163,20 @@ static FORCE_INLINE void *taosDecodeFixed64(void *buf, uint64_t *value) {
|
|||
return POINTER_SHIFT(buf, sizeof(*value));
|
||||
}
|
||||
|
||||
static FORCE_INLINE void *taosEncodeVariant16(void *buf, uint16_t value) {
|
||||
// ---- Fixed I64
|
||||
static FORCE_INLINE void *taosEncodeFixedI64(void *buf, int64_t value) {
|
||||
return taosEncodeFixedU64(buf, ZIGZAGE(int64_t, value));
|
||||
}
|
||||
|
||||
static FORCE_INLINE void *taosDecodeFixedI64(void *buf, int64_t *value) {
|
||||
uint64_t tvalue = 0;
|
||||
void * ret = taosDecodeFixedU64(buf, &tvalue);
|
||||
*value = ZIGZAGD(int64_t, tvalue);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// ---- Variant U16
|
||||
static FORCE_INLINE void *taosEncodeVariantU16(void *buf, uint16_t value) {
|
||||
int i = 0;
|
||||
while (value >= ENCODE_LIMIT) {
|
||||
((uint8_t *)buf)[i] = (value | ENCODE_LIMIT);
|
||||
|
@ -132,39 +187,11 @@ static FORCE_INLINE void *taosEncodeVariant16(void *buf, uint16_t value) {
|
|||
|
||||
((uint8_t *)buf)[i] = value;
|
||||
|
||||
return POINTER_SHIFT(buf, i+1);
|
||||
}
|
||||
|
||||
static FORCE_INLINE void *taosEncodeVariant32(void *buf, uint32_t value) {
|
||||
int i = 0;
|
||||
while (value >= ENCODE_LIMIT) {
|
||||
((uint8_t *)buf)[i] = (value | ENCODE_LIMIT);
|
||||
value >>= 7;
|
||||
i++;
|
||||
ASSERT(i < 5);
|
||||
}
|
||||
|
||||
((uint8_t *)buf)[i] = value;
|
||||
|
||||
return POINTER_SHIFT(buf, i + 1);
|
||||
}
|
||||
|
||||
static FORCE_INLINE void *taosEncodeVariant64(void *buf, uint64_t value) {
|
||||
int i = 0;
|
||||
while (value >= ENCODE_LIMIT) {
|
||||
((uint8_t *)buf)[i] = (value | ENCODE_LIMIT);
|
||||
value >>= 7;
|
||||
i++;
|
||||
ASSERT(i < 10);
|
||||
}
|
||||
|
||||
((uint8_t *)buf)[i] = value;
|
||||
|
||||
return POINTER_SHIFT(buf, i + 1);
|
||||
}
|
||||
|
||||
static FORCE_INLINE void *taosDecodeVariant16(void *buf, uint16_t *value) {
|
||||
int i = 0;
|
||||
static FORCE_INLINE void *taosDecodeVariantU16(void *buf, uint16_t *value) {
|
||||
int i = 0;
|
||||
uint16_t tval = 0;
|
||||
*value = 0;
|
||||
while (i < 3) {
|
||||
|
@ -181,8 +208,35 @@ static FORCE_INLINE void *taosDecodeVariant16(void *buf, uint16_t *value) {
|
|||
return NULL; // error happened
|
||||
}
|
||||
|
||||
static FORCE_INLINE void *taosDecodeVariant32(void *buf, uint32_t *value) {
|
||||
// ---- Variant I16
|
||||
static FORCE_INLINE void *taosEncodeVariantI16(void *buf, int16_t value) {
|
||||
return taosEncodeVariantU16(buf, ZIGZAGE(int16_t, value));
|
||||
}
|
||||
|
||||
static FORCE_INLINE void *taosDecodeVariantI16(void *buf, int16_t *value) {
|
||||
uint16_t tvalue = 0;
|
||||
void * ret = taosDecodeVariantU16(buf, &tvalue);
|
||||
*value = ZIGZAGD(int16_t, tvalue);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// ---- Variant U32
|
||||
static FORCE_INLINE void *taosEncodeVariantU32(void *buf, uint32_t value) {
|
||||
int i = 0;
|
||||
while (value >= ENCODE_LIMIT) {
|
||||
((uint8_t *)buf)[i] = (value | ENCODE_LIMIT);
|
||||
value >>= 7;
|
||||
i++;
|
||||
ASSERT(i < 5);
|
||||
}
|
||||
|
||||
((uint8_t *)buf)[i] = value;
|
||||
|
||||
return POINTER_SHIFT(buf, i + 1);
|
||||
}
|
||||
|
||||
static FORCE_INLINE void *taosDecodeVariantU32(void *buf, uint32_t *value) {
|
||||
int i = 0;
|
||||
uint32_t tval = 0;
|
||||
*value = 0;
|
||||
while (i < 5) {
|
||||
|
@ -199,8 +253,35 @@ static FORCE_INLINE void *taosDecodeVariant32(void *buf, uint32_t *value) {
|
|||
return NULL; // error happened
|
||||
}
|
||||
|
||||
static FORCE_INLINE void *taosDecodeVariant64(void *buf, uint64_t *value) {
|
||||
// ---- Variant I32
|
||||
static FORCE_INLINE void *taosEncodeVariantI32(void *buf, int32_t value) {
|
||||
return taosEncodeVariantU32(buf, ZIGZAGE(int32_t, value));
|
||||
}
|
||||
|
||||
static FORCE_INLINE void *taosDecodeVariantI32(void *buf, int32_t *value) {
|
||||
uint32_t tvalue = 0;
|
||||
void * ret = taosDecodeVariantU32(buf, &tvalue);
|
||||
*value = ZIGZAGD(int32_t, tvalue);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// ---- Variant U64
|
||||
static FORCE_INLINE void *taosEncodeVariantU64(void *buf, uint64_t value) {
|
||||
int i = 0;
|
||||
while (value >= ENCODE_LIMIT) {
|
||||
((uint8_t *)buf)[i] = (value | ENCODE_LIMIT);
|
||||
value >>= 7;
|
||||
i++;
|
||||
ASSERT(i < 10);
|
||||
}
|
||||
|
||||
((uint8_t *)buf)[i] = value;
|
||||
|
||||
return POINTER_SHIFT(buf, i + 1);
|
||||
}
|
||||
|
||||
static FORCE_INLINE void *taosDecodeVariantU64(void *buf, uint64_t *value) {
|
||||
int i = 0;
|
||||
uint64_t tval = 0;
|
||||
*value = 0;
|
||||
while (i < 10) {
|
||||
|
@ -217,10 +298,23 @@ static FORCE_INLINE void *taosDecodeVariant64(void *buf, uint64_t *value) {
|
|||
return NULL; // error happened
|
||||
}
|
||||
|
||||
// ---- Variant I64
|
||||
static FORCE_INLINE void *taosEncodeVariantI64(void *buf, int64_t value) {
|
||||
return taosEncodeVariantU64(buf, ZIGZAGE(int64_t, value));
|
||||
}
|
||||
|
||||
static FORCE_INLINE void *taosDecodeVariantI64(void *buf, int64_t *value) {
|
||||
uint64_t tvalue = 0;
|
||||
void * ret = taosDecodeVariantU64(buf, &tvalue);
|
||||
*value = ZIGZAGD(int64_t, tvalue);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// ---- string
|
||||
static FORCE_INLINE void *taosEncodeString(void *buf, char *value) {
|
||||
size_t size = strlen(value);
|
||||
|
||||
buf = taosEncodeVariant64(buf, size);
|
||||
buf = taosEncodeVariantU64(buf, size);
|
||||
memcpy(buf, value, size);
|
||||
|
||||
return POINTER_SHIFT(buf, size);
|
||||
|
@ -229,7 +323,7 @@ static FORCE_INLINE void *taosEncodeString(void *buf, char *value) {
|
|||
static FORCE_INLINE void *taosDecodeString(void *buf, char **value) {
|
||||
uint64_t size = 0;
|
||||
|
||||
buf = taosDecodeVariant64(buf, &size);
|
||||
buf = taosDecodeVariantU64(buf, &size);
|
||||
*value = (char *)malloc(size + 1);
|
||||
if (*value == NULL) return NULL;
|
||||
memcpy(*value, buf, size);
|
||||
|
|
|
@ -46,6 +46,7 @@ extern "C" {
|
|||
|
||||
// Pointer p drift right by b bytes
|
||||
#define POINTER_SHIFT(p, b) ((void *)((char *)(p) + (b)))
|
||||
#define POINTER_DISTANCE(p1, p2) ((char *)(p1) - (char *)(p2))
|
||||
|
||||
#ifndef NDEBUG
|
||||
#define ASSERT(x) assert(x)
|
||||
|
@ -124,6 +125,8 @@ int64_t strnatoi(char *num, int32_t len);
|
|||
|
||||
char* strreplace(const char* str, const char* pattern, const char* rep);
|
||||
|
||||
char *strbetween(char *string, char *begin, char *end);
|
||||
|
||||
char *paGetToken(char *src, char **token, int32_t *tokenLen);
|
||||
|
||||
void taosMsleep(int32_t mseconds);
|
||||
|
|
|
@ -83,17 +83,10 @@ static FORCE_INLINE int32_t taosHashCapacity(int32_t length) {
|
|||
int32_t len = MIN(length, HASH_MAX_CAPACITY);
|
||||
|
||||
uint32_t i = 4;
|
||||
while (i < len) i = (i << 1U);
|
||||
while (i < len) i = (i << 1u);
|
||||
return i;
|
||||
}
|
||||
|
||||
/**
|
||||
* inplace update node in hash table
|
||||
* @param pHashObj hash table object
|
||||
* @param pNode hash data node
|
||||
*/
|
||||
static void doUpdateHashTable(SHashObj *pHashObj, SHashNode *pNode);
|
||||
|
||||
/**
|
||||
* Get SHashNode from hashlist, nodes from trash are not included.
|
||||
* @param pHashObj Cache objection
|
||||
|
@ -105,10 +98,9 @@ static void doUpdateHashTable(SHashObj *pHashObj, SHashNode *pNode);
|
|||
FORCE_INLINE SHashNode *doGetNodeFromHashTable(SHashObj *pHashObj, const void *key, uint32_t keyLen, uint32_t *hashVal) {
|
||||
uint32_t hash = (*pHashObj->hashFp)(key, keyLen);
|
||||
|
||||
int32_t slot = HASH_INDEX(hash, pHashObj->capacity);
|
||||
SHashEntry *pEntry = pHashObj->hashList[slot];
|
||||
int32_t slot = HASH_INDEX(hash, pHashObj->capacity);
|
||||
SHashNode *pNode = pHashObj->hashList[slot];
|
||||
|
||||
SHashNode *pNode = pEntry->next;
|
||||
while (pNode) {
|
||||
if ((pNode->keyLen == keyLen) && (memcmp(pNode->key, key, keyLen) == 0)) {
|
||||
break;
|
||||
|
@ -190,17 +182,13 @@ SHashObj *taosHashInit(size_t capacity, _hash_fn_t fn, bool threadsafe) {
|
|||
|
||||
pHashObj->hashFp = fn;
|
||||
|
||||
pHashObj->hashList = (SHashEntry **)calloc(pHashObj->capacity, sizeof(SHashEntry *));
|
||||
pHashObj->hashList = (SHashNode **)calloc(pHashObj->capacity, POINTER_BYTES);
|
||||
if (pHashObj->hashList == NULL) {
|
||||
free(pHashObj);
|
||||
uError("failed to allocate memory, reason:%s", strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (int32_t i = 0; i < pHashObj->capacity; ++i) {
|
||||
pHashObj->hashList[i] = calloc(1, sizeof(SHashEntry));
|
||||
}
|
||||
|
||||
if (threadsafe) {
|
||||
#if defined(LINUX)
|
||||
pHashObj->lock = calloc(1, sizeof(pthread_rwlock_t));
|
||||
|
@ -252,7 +240,18 @@ int32_t taosHashPut(SHashObj *pHashObj, const void *key, size_t keyLen, void *da
|
|||
return -1;
|
||||
}
|
||||
|
||||
doUpdateHashTable(pHashObj, pNewNode);
|
||||
if (pNewNode->prev) {
|
||||
pNewNode->prev->next = pNewNode;
|
||||
} else {
|
||||
int32_t slot = HASH_INDEX(pNewNode->hashVal, pHashObj->capacity);
|
||||
|
||||
assert(pHashObj->hashList[slot] == pNode);
|
||||
pHashObj->hashList[slot] = pNewNode;
|
||||
}
|
||||
|
||||
if (pNewNode->next) {
|
||||
(pNewNode->next)->prev = pNewNode;
|
||||
}
|
||||
}
|
||||
|
||||
__unlock(pHashObj->lock);
|
||||
|
@ -287,24 +286,19 @@ void taosHashRemove(SHashObj *pHashObj, const void *key, size_t keyLen) {
|
|||
}
|
||||
|
||||
SHashNode *pNext = pNode->next;
|
||||
if (pNode->prev != NULL) {
|
||||
if (pNode->prev == NULL) {
|
||||
int32_t slot = HASH_INDEX(val, pHashObj->capacity);
|
||||
if (pHashObj->hashList[slot]->next == pNode) {
|
||||
pHashObj->hashList[slot]->next = pNext;
|
||||
} else {
|
||||
pNode->prev->next = pNext;
|
||||
}
|
||||
assert(pHashObj->hashList[slot] == pNode);
|
||||
|
||||
pHashObj->hashList[slot] = pNext;
|
||||
} else {
|
||||
pNode->prev->next = pNext;
|
||||
}
|
||||
|
||||
|
||||
if (pNext != NULL) {
|
||||
pNext->prev = pNode->prev;
|
||||
}
|
||||
|
||||
uint32_t index = HASH_INDEX(pNode->hashVal, pHashObj->capacity);
|
||||
|
||||
SHashEntry *pEntry = pHashObj->hashList[index];
|
||||
pEntry->num--;
|
||||
|
||||
pHashObj->size--;
|
||||
|
||||
pNode->next = NULL;
|
||||
|
@ -325,8 +319,7 @@ void taosHashCleanup(SHashObj *pHashObj) {
|
|||
|
||||
if (pHashObj->hashList) {
|
||||
for (int32_t i = 0; i < pHashObj->capacity; ++i) {
|
||||
SHashEntry *pEntry = pHashObj->hashList[i];
|
||||
pNode = pEntry->next;
|
||||
pNode = pHashObj->hashList[i];
|
||||
|
||||
while (pNode) {
|
||||
pNext = pNode->next;
|
||||
|
@ -337,8 +330,6 @@ void taosHashCleanup(SHashObj *pHashObj) {
|
|||
free(pNode);
|
||||
pNode = pNext;
|
||||
}
|
||||
|
||||
tfree(pEntry);
|
||||
}
|
||||
|
||||
free(pHashObj->hashList);
|
||||
|
@ -385,13 +376,13 @@ bool taosHashIterNext(SHashMutableIterator *pIter) {
|
|||
assert(pIter->pCur == NULL && pIter->pNext == NULL);
|
||||
|
||||
while (1) {
|
||||
SHashEntry *pEntry = pIter->pHashObj->hashList[pIter->entryIndex];
|
||||
if (pEntry->next == NULL) {
|
||||
SHashNode *pEntry = pIter->pHashObj->hashList[pIter->entryIndex];
|
||||
if (pEntry == NULL) {
|
||||
pIter->entryIndex++;
|
||||
continue;
|
||||
}
|
||||
|
||||
pIter->pCur = pEntry->next;
|
||||
pIter->pCur = pEntry;
|
||||
|
||||
if (pIter->pCur->next) {
|
||||
pIter->pNext = pIter->pCur->next;
|
||||
|
@ -444,25 +435,25 @@ int32_t taosHashGetMaxOverflowLinkLength(const SHashObj *pHashObj) {
|
|||
int32_t num = 0;
|
||||
|
||||
for (int32_t i = 0; i < pHashObj->size; ++i) {
|
||||
SHashEntry *pEntry = pHashObj->hashList[i];
|
||||
if (num < pEntry->num) {
|
||||
num = pEntry->num;
|
||||
SHashNode *pEntry = pHashObj->hashList[i];
|
||||
if (pEntry == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int32_t j = 0;
|
||||
while(pEntry != NULL) {
|
||||
pEntry = pEntry->next;
|
||||
j++;
|
||||
}
|
||||
|
||||
if (num < j) {
|
||||
num = j;
|
||||
}
|
||||
}
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
void doUpdateHashTable(SHashObj *pHashObj, SHashNode *pNode) {
|
||||
if (pNode->prev1) {
|
||||
pNode->prev1->next = pNode;
|
||||
}
|
||||
|
||||
if (pNode->next) {
|
||||
(pNode->next)->prev = pNode;
|
||||
}
|
||||
}
|
||||
|
||||
void taosHashTableResize(SHashObj *pHashObj) {
|
||||
if (pHashObj->size < pHashObj->capacity * HASH_DEFAULT_LOAD_FACTOR) {
|
||||
return;
|
||||
|
@ -479,69 +470,53 @@ void taosHashTableResize(SHashObj *pHashObj) {
|
|||
return;
|
||||
}
|
||||
|
||||
// int64_t st = taosGetTimestampUs();
|
||||
|
||||
SHashEntry **pNewEntry = realloc(pHashObj->hashList, sizeof(SHashEntry *) * newSize);
|
||||
if (pNewEntry == NULL) {
|
||||
void *pNewEntry = realloc(pHashObj->hashList, POINTER_BYTES * newSize);
|
||||
if (pNewEntry == NULL) {// todo handle error
|
||||
// uTrace("cache resize failed due to out of memory, capacity remain:%d", pHashObj->capacity);
|
||||
return;
|
||||
}
|
||||
|
||||
pHashObj->hashList = pNewEntry;
|
||||
for (int32_t i = pHashObj->capacity; i < newSize; ++i) {
|
||||
pHashObj->hashList[i] = calloc(1, sizeof(SHashEntry));
|
||||
}
|
||||
memset(&pHashObj->hashList[pHashObj->capacity], 0, POINTER_BYTES * (newSize - pHashObj->capacity));
|
||||
|
||||
pHashObj->capacity = newSize;
|
||||
|
||||
for (int32_t i = 0; i < pHashObj->capacity; ++i) {
|
||||
SHashEntry *pEntry = pHashObj->hashList[i];
|
||||
|
||||
pNode = pEntry->next;
|
||||
pNode = pHashObj->hashList[i];
|
||||
if (pNode != NULL) {
|
||||
assert(pNode->prev1 == pEntry && pEntry->num > 0);
|
||||
assert(pNode->prev == NULL);
|
||||
}
|
||||
|
||||
while (pNode) {
|
||||
int32_t j = HASH_INDEX(pNode->hashVal, pHashObj->capacity);
|
||||
if (j == i) { // this key resides in the same slot, no need to relocate it
|
||||
if (j == i) { // this key locates in the same slot, no need to relocate it
|
||||
pNode = pNode->next;
|
||||
} else {
|
||||
pNext = pNode->next;
|
||||
|
||||
// remove from current slot
|
||||
assert(pNode->prev1 != NULL);
|
||||
|
||||
if (pNode->prev1 == pEntry) { // first node of the overflow linked list
|
||||
pEntry->next = pNode->next;
|
||||
if (pNode->prev == NULL) { // first node of the overflow linked list
|
||||
pHashObj->hashList[i] = pNext;
|
||||
} else {
|
||||
pNode->prev->next = pNode->next;
|
||||
pNode->prev->next = pNext;
|
||||
}
|
||||
|
||||
pEntry->num--;
|
||||
assert(pEntry->num >= 0);
|
||||
|
||||
if (pNode->next != NULL) {
|
||||
(pNode->next)->prev = pNode->prev;
|
||||
if (pNext != NULL) {
|
||||
pNext->prev = pNode->prev;
|
||||
}
|
||||
|
||||
// clear pointer
|
||||
pNode->next = NULL;
|
||||
pNode->prev = NULL;
|
||||
|
||||
// added into new slot
|
||||
pNode->next = NULL;
|
||||
pNode->prev1 = NULL;
|
||||
|
||||
SHashEntry *pNewIndexEntry = pHashObj->hashList[j];
|
||||
|
||||
if (pNewIndexEntry->next != NULL) {
|
||||
assert(pNewIndexEntry->next->prev1 == pNewIndexEntry);
|
||||
|
||||
pNewIndexEntry->next->prev = pNode;
|
||||
SHashNode *pNew = pHashObj->hashList[j];
|
||||
if (pNew != NULL) {
|
||||
assert(pNew->prev == NULL);
|
||||
pNew->prev = pNode;
|
||||
}
|
||||
|
||||
pNode->next = pNewIndexEntry->next;
|
||||
pNode->prev1 = pNewIndexEntry;
|
||||
|
||||
pNewIndexEntry->next = pNode;
|
||||
pNewIndexEntry->num++;
|
||||
pNode->next = pNew;
|
||||
pHashObj->hashList[j] = pNode;
|
||||
|
||||
// continue
|
||||
pNode = pNext;
|
||||
|
@ -549,7 +524,6 @@ void taosHashTableResize(SHashObj *pHashObj) {
|
|||
}
|
||||
}
|
||||
|
||||
// int64_t et = taosGetTimestampUs();
|
||||
// uTrace("hash table resize completed, new capacity:%d, load factor:%f, elapsed time:%fms", pHashObj->capacity,
|
||||
// ((double)pHashObj->size) / pHashObj->capacity, (et - st) / 1000.0);
|
||||
}
|
||||
|
@ -595,19 +569,17 @@ SHashNode *doUpdateHashNode(SHashNode *pNode, const void *key, size_t keyLen, co
|
|||
void doAddToHashTable(SHashObj *pHashObj, SHashNode *pNode) {
|
||||
assert(pNode != NULL);
|
||||
|
||||
int32_t index = HASH_INDEX(pNode->hashVal, pHashObj->capacity);
|
||||
SHashEntry *pEntry = pHashObj->hashList[index];
|
||||
int32_t index = HASH_INDEX(pNode->hashVal, pHashObj->capacity);
|
||||
|
||||
pNode->next = pEntry->next;
|
||||
|
||||
if (pEntry->next) {
|
||||
pEntry->next->prev = pNode;
|
||||
SHashNode* pEntry = pHashObj->hashList[index];
|
||||
if (pEntry != NULL) {
|
||||
pEntry->prev = pNode;
|
||||
|
||||
pNode->next = pEntry;
|
||||
pNode->prev = NULL;
|
||||
}
|
||||
|
||||
pEntry->next = pNode;
|
||||
pNode->prev1 = pEntry;
|
||||
|
||||
pEntry->num++;
|
||||
pHashObj->hashList[index] = pNode;
|
||||
pHashObj->size++;
|
||||
}
|
||||
|
||||
|
@ -616,13 +588,13 @@ SHashNode *getNextHashNode(SHashMutableIterator *pIter) {
|
|||
|
||||
pIter->entryIndex++;
|
||||
while (pIter->entryIndex < pIter->pHashObj->capacity) {
|
||||
SHashEntry *pEntry = pIter->pHashObj->hashList[pIter->entryIndex];
|
||||
if (pEntry->next == NULL) {
|
||||
SHashNode *pNode = pIter->pHashObj->hashList[pIter->entryIndex];
|
||||
if (pNode == NULL) {
|
||||
pIter->entryIndex++;
|
||||
continue;
|
||||
}
|
||||
|
||||
return pEntry->next;
|
||||
return pNode;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
|
|
|
@ -92,7 +92,7 @@ int32_t compareLenPrefixedWStr(const void *pLeft, const void *pRight) {
|
|||
if (len1 != len2) {
|
||||
return len1 > len2? 1:-1;
|
||||
} else {
|
||||
int32_t ret = wcsncmp(varDataVal(pLeft), varDataVal(pRight), len1);
|
||||
int32_t ret = wcsncmp(varDataVal(pLeft), varDataVal(pRight), len1/TSDB_NCHAR_SIZE);
|
||||
if (ret == 0) {
|
||||
return 0;
|
||||
} else {
|
||||
|
|
|
@ -331,6 +331,20 @@ char *strreplace(const char *str, const char *pattern, const char *rep) {
|
|||
return dest;
|
||||
}
|
||||
|
||||
char *strbetween(char *string, char *begin, char *end) {
|
||||
char *result = NULL;
|
||||
char *_begin = strstr(string, begin);
|
||||
if (_begin != NULL) {
|
||||
char *_end = strstr(_begin + strlen(begin), end);
|
||||
int size = _end - _begin;
|
||||
if (_end != NULL && size > 0) {
|
||||
result = (char *)calloc(1, size);
|
||||
memcpy(result, _begin + strlen(begin), size - +strlen(begin));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int32_t taosByteArrayToHexStr(char bytes[], int32_t len, char hexstr[]) {
|
||||
int32_t i;
|
||||
char hexval[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
|
||||
|
@ -691,4 +705,4 @@ void taosRemoveDir(char *rootDir) {
|
|||
rmdir(rootDir);
|
||||
|
||||
uPrint("dir:%s is removed", rootDir);
|
||||
}
|
||||
}
|
|
@ -9,8 +9,18 @@ static bool test_fixed_uint16(uint16_t value) {
|
|||
char buf[20] = "\0";
|
||||
uint16_t value_check = 0;
|
||||
|
||||
void *ptr1 = taosEncodeFixed16(static_cast<void *>(buf), value);
|
||||
void *ptr2 = taosDecodeFixed16(static_cast<void *>(buf), &value_check);
|
||||
void *ptr1 = taosEncodeFixedU16(static_cast<void *>(buf), value);
|
||||
void *ptr2 = taosDecodeFixedU16(static_cast<void *>(buf), &value_check);
|
||||
|
||||
return ((ptr2 != NULL) && (value == value_check) && (ptr1 == ptr2));
|
||||
}
|
||||
|
||||
static bool test_fixed_int16(int16_t value) {
|
||||
char buf[20] = "\0";
|
||||
int16_t value_check = 0;
|
||||
|
||||
void *ptr1 = taosEncodeFixedI16(static_cast<void *>(buf), value);
|
||||
void *ptr2 = taosDecodeFixedI16(static_cast<void *>(buf), &value_check);
|
||||
|
||||
return ((ptr2 != NULL) && (value == value_check) && (ptr1 == ptr2));
|
||||
}
|
||||
|
@ -19,8 +29,18 @@ static bool test_fixed_uint32(uint32_t value) {
|
|||
char buf[20] = "\0";
|
||||
uint32_t value_check = 0;
|
||||
|
||||
void *ptr1 = taosEncodeFixed32(static_cast<void *>(buf), value);
|
||||
void *ptr2 = taosDecodeFixed32(static_cast<void *>(buf), &value_check);
|
||||
void *ptr1 = taosEncodeFixedU32(static_cast<void *>(buf), value);
|
||||
void *ptr2 = taosDecodeFixedU32(static_cast<void *>(buf), &value_check);
|
||||
|
||||
return ((ptr2 != NULL) && (value == value_check) && (ptr1 == ptr2));
|
||||
}
|
||||
|
||||
static bool test_fixed_int32(int32_t value) {
|
||||
char buf[20] = "\0";
|
||||
int32_t value_check = 0;
|
||||
|
||||
void *ptr1 = taosEncodeFixedI32(static_cast<void *>(buf), value);
|
||||
void *ptr2 = taosDecodeFixedI32(static_cast<void *>(buf), &value_check);
|
||||
|
||||
return ((ptr2 != NULL) && (value == value_check) && (ptr1 == ptr2));
|
||||
}
|
||||
|
@ -29,8 +49,18 @@ static bool test_fixed_uint64(uint64_t value) {
|
|||
char buf[20] = "\0";
|
||||
uint64_t value_check = 0;
|
||||
|
||||
void *ptr1 = taosEncodeFixed64(static_cast<void *>(buf), value);
|
||||
void *ptr2 = taosDecodeFixed64(static_cast<void *>(buf), &value_check);
|
||||
void *ptr1 = taosEncodeFixedU64(static_cast<void *>(buf), value);
|
||||
void *ptr2 = taosDecodeFixedU64(static_cast<void *>(buf), &value_check);
|
||||
|
||||
return ((ptr2 != NULL) && (value == value_check) && (ptr1 == ptr2));
|
||||
}
|
||||
|
||||
static bool test_fixed_int64(int64_t value) {
|
||||
char buf[20] = "\0";
|
||||
int64_t value_check = 0;
|
||||
|
||||
void *ptr1 = taosEncodeFixedI64(static_cast<void *>(buf), value);
|
||||
void *ptr2 = taosDecodeFixedI64(static_cast<void *>(buf), &value_check);
|
||||
|
||||
return ((ptr2 != NULL) && (value == value_check) && (ptr1 == ptr2));
|
||||
}
|
||||
|
@ -39,8 +69,18 @@ static bool test_variant_uint16(uint16_t value) {
|
|||
char buf[20] = "\0";
|
||||
uint16_t value_check = 0;
|
||||
|
||||
void *ptr1 = taosEncodeVariant16(static_cast<void *>(buf), value);
|
||||
void *ptr2 = taosDecodeVariant16(static_cast<void *>(buf), &value_check);
|
||||
void *ptr1 = taosEncodeVariantU16(static_cast<void *>(buf), value);
|
||||
void *ptr2 = taosDecodeVariantU16(static_cast<void *>(buf), &value_check);
|
||||
|
||||
return ((ptr2 != NULL) && (value == value_check) && (ptr1 == ptr2));
|
||||
}
|
||||
|
||||
static bool test_variant_int16(int16_t value) {
|
||||
char buf[20] = "\0";
|
||||
int16_t value_check = 0;
|
||||
|
||||
void *ptr1 = taosEncodeVariantI16(static_cast<void *>(buf), value);
|
||||
void *ptr2 = taosDecodeVariantI16(static_cast<void *>(buf), &value_check);
|
||||
|
||||
return ((ptr2 != NULL) && (value == value_check) && (ptr1 == ptr2));
|
||||
}
|
||||
|
@ -49,8 +89,18 @@ static bool test_variant_uint32(uint32_t value) {
|
|||
char buf[20] = "\0";
|
||||
uint32_t value_check = 0;
|
||||
|
||||
void *ptr1 = taosEncodeVariant32(static_cast<void *>(buf), value);
|
||||
void *ptr2 = taosDecodeVariant32(static_cast<void *>(buf), &value_check);
|
||||
void *ptr1 = taosEncodeVariantU32(static_cast<void *>(buf), value);
|
||||
void *ptr2 = taosDecodeVariantU32(static_cast<void *>(buf), &value_check);
|
||||
|
||||
return ((ptr2 != NULL) && (value == value_check) && (ptr1 == ptr2));
|
||||
}
|
||||
|
||||
static bool test_variant_int32(int32_t value) {
|
||||
char buf[20] = "\0";
|
||||
int32_t value_check = 0;
|
||||
|
||||
void *ptr1 = taosEncodeVariantI32(static_cast<void *>(buf), value);
|
||||
void *ptr2 = taosDecodeVariantI32(static_cast<void *>(buf), &value_check);
|
||||
|
||||
return ((ptr2 != NULL) && (value == value_check) && (ptr1 == ptr2));
|
||||
}
|
||||
|
@ -59,8 +109,18 @@ static bool test_variant_uint64(uint64_t value) {
|
|||
char buf[20] = "\0";
|
||||
uint64_t value_check = 0;
|
||||
|
||||
void *ptr1 = taosEncodeVariant64(static_cast<void *>(buf), value);
|
||||
void *ptr2 = taosDecodeVariant64(static_cast<void *>(buf), &value_check);
|
||||
void *ptr1 = taosEncodeVariantU64(static_cast<void *>(buf), value);
|
||||
void *ptr2 = taosDecodeVariantU64(static_cast<void *>(buf), &value_check);
|
||||
|
||||
return ((ptr2 != NULL) && (value == value_check) && (ptr1 == ptr2));
|
||||
}
|
||||
|
||||
static bool test_variant_int64(int64_t value) {
|
||||
char buf[20] = "\0";
|
||||
int64_t value_check = 0;
|
||||
|
||||
void *ptr1 = taosEncodeVariantI64(static_cast<void *>(buf), value);
|
||||
void *ptr2 = taosDecodeVariantI64(static_cast<void *>(buf), &value_check);
|
||||
|
||||
return ((ptr2 != NULL) && (value == value_check) && (ptr1 == ptr2));
|
||||
}
|
||||
|
@ -68,49 +128,111 @@ static bool test_variant_uint64(uint64_t value) {
|
|||
TEST(codingTest, fixed_encode_decode) {
|
||||
srand(time(0));
|
||||
|
||||
// uint16_t
|
||||
for (uint16_t value = 0; value <= UINT16_MAX; value++) {
|
||||
ASSERT_TRUE(test_fixed_uint16(value));
|
||||
if (value == UINT16_MAX) break;
|
||||
}
|
||||
|
||||
ASSERT_TRUE(test_fixed_uint32(0));
|
||||
ASSERT_TRUE(test_fixed_uint32(UINT32_MAX));
|
||||
|
||||
for (int i = 0; i < 1000000; i++) {
|
||||
ASSERT_TRUE(test_fixed_uint32(rand()));
|
||||
// int16_t
|
||||
for (int16_t value = INT16_MIN; value <= INT16_MAX; value++) {
|
||||
ASSERT_TRUE(test_fixed_int16(value));
|
||||
if (value == INT16_MAX) break;
|
||||
}
|
||||
|
||||
std::mt19937_64 gen (std::random_device{}());
|
||||
std::mt19937 gen32(std::random_device{}());
|
||||
// uint32_t
|
||||
ASSERT_TRUE(test_fixed_uint32(0));
|
||||
ASSERT_TRUE(test_fixed_uint32(UINT32_MAX));
|
||||
std::uniform_int_distribution<uint32_t> distr1(0, UINT32_MAX);
|
||||
|
||||
for (int i = 0; i < 1000000; i++) {
|
||||
ASSERT_TRUE(test_fixed_uint32(distr1(gen32)));
|
||||
}
|
||||
|
||||
// int32_t
|
||||
ASSERT_TRUE(test_fixed_int32(INT32_MIN));
|
||||
ASSERT_TRUE(test_fixed_int32(INT32_MAX));
|
||||
std::uniform_int_distribution<int32_t> distr2(INT32_MIN, INT32_MAX);
|
||||
|
||||
for (int i = 0; i < 1000000; i++) {
|
||||
ASSERT_TRUE(test_fixed_int32(distr2(gen32)));
|
||||
}
|
||||
|
||||
std::mt19937_64 gen64(std::random_device{}());
|
||||
// uint64_t
|
||||
std::uniform_int_distribution<uint64_t> distr3(0, UINT64_MAX);
|
||||
|
||||
ASSERT_TRUE(test_fixed_uint64(0));
|
||||
ASSERT_TRUE(test_fixed_uint64(UINT64_MAX));
|
||||
for (int i = 0; i < 1000000; i++) {
|
||||
ASSERT_TRUE(test_fixed_uint64(gen()));
|
||||
ASSERT_TRUE(test_fixed_uint64(distr3(gen64)));
|
||||
}
|
||||
|
||||
// int64_t
|
||||
std::uniform_int_distribution<int64_t> distr4(INT64_MIN, INT64_MAX);
|
||||
|
||||
ASSERT_TRUE(test_fixed_int64(INT64_MIN));
|
||||
ASSERT_TRUE(test_fixed_int64(INT64_MAX));
|
||||
for (int i = 0; i < 1000000; i++) {
|
||||
ASSERT_TRUE(test_fixed_int64(distr4(gen64)));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(codingTest, variant_encode_decode) {
|
||||
srand(time(0));
|
||||
|
||||
// uint16_t
|
||||
for (uint16_t value = 0; value <= UINT16_MAX; value++) {
|
||||
ASSERT_TRUE(test_variant_uint16(value));
|
||||
if (value == UINT16_MAX) break;
|
||||
}
|
||||
|
||||
// int16_t
|
||||
for (int16_t value = INT16_MIN; value <= INT16_MAX; value++) {
|
||||
ASSERT_TRUE(test_variant_int16(value));
|
||||
if (value == INT16_MAX) break;
|
||||
}
|
||||
|
||||
std::mt19937 gen32(std::random_device{}());
|
||||
// uint32_t
|
||||
std::uniform_int_distribution<uint32_t> distr1(0, UINT32_MAX);
|
||||
ASSERT_TRUE(test_variant_uint32(0));
|
||||
ASSERT_TRUE(test_variant_uint32(UINT32_MAX));
|
||||
|
||||
for (int i = 0; i < 5000000; i++) {
|
||||
ASSERT_TRUE(test_variant_uint32(rand()));
|
||||
ASSERT_TRUE(test_variant_uint32(distr1(gen32)));
|
||||
}
|
||||
|
||||
std::mt19937_64 gen (std::random_device{}());
|
||||
// int32_t
|
||||
std::uniform_int_distribution<int32_t> distr2(INT32_MIN, INT32_MAX);
|
||||
ASSERT_TRUE(test_variant_int32(INT32_MIN));
|
||||
ASSERT_TRUE(test_variant_int32(INT32_MAX));
|
||||
|
||||
for (int i = 0; i < 5000000; i++) {
|
||||
ASSERT_TRUE(test_variant_int32(distr2(gen32)));
|
||||
}
|
||||
|
||||
std::mt19937_64 gen64(std::random_device{}());
|
||||
// uint64_t
|
||||
std::uniform_int_distribution<uint64_t> distr3(0, UINT64_MAX);
|
||||
|
||||
ASSERT_TRUE(test_variant_uint64(0));
|
||||
ASSERT_TRUE(test_variant_uint64(UINT64_MAX));
|
||||
for (int i = 0; i < 5000000; i++) {
|
||||
uint64_t value = gen();
|
||||
// uint64_t value = gen();
|
||||
// printf("%ull\n", value);
|
||||
ASSERT_TRUE(test_variant_uint64(value));
|
||||
ASSERT_TRUE(test_variant_uint64(distr3(gen64)));
|
||||
}
|
||||
|
||||
// int64_t
|
||||
std::uniform_int_distribution<int64_t> distr4(INT64_MIN, INT64_MAX);
|
||||
|
||||
ASSERT_TRUE(test_variant_int64(INT64_MIN));
|
||||
ASSERT_TRUE(test_variant_int64(INT64_MAX));
|
||||
for (int i = 0; i < 5000000; i++) {
|
||||
// uint64_t value = gen();
|
||||
// printf("%ull\n", value);
|
||||
ASSERT_TRUE(test_variant_int64(distr4(gen64)));
|
||||
}
|
||||
}
|
|
@ -149,8 +149,8 @@ int main(int argc, char** argv) {
|
|||
}
|
||||
|
||||
TEST(testCase, hashTest) {
|
||||
// simpleTest();
|
||||
// stringKeyTest();
|
||||
// noLockPerformanceTest();
|
||||
// multithreadsTest();
|
||||
simpleTest();
|
||||
stringKeyTest();
|
||||
noLockPerformanceTest();
|
||||
multithreadsTest();
|
||||
}
|
|
@ -29,6 +29,8 @@
|
|||
#include "vnode.h"
|
||||
#include "vnodeInt.h"
|
||||
|
||||
#define TSDB_VNODE_VERSION_CONTENT_LEN 31
|
||||
|
||||
static int32_t tsOpennedVnodes;
|
||||
static void *tsDnodeVnodesHash;
|
||||
static void vnodeCleanUp(SVnodeObj *pVnode);
|
||||
|
@ -108,7 +110,7 @@ int32_t vnodeCreate(SMDCreateVnodeMsg *pVnodeCfg) {
|
|||
tsdbCfg.maxRowsPerFileBlock = pVnodeCfg->cfg.maxRowsPerFileBlock;
|
||||
tsdbCfg.precision = pVnodeCfg->cfg.precision;
|
||||
tsdbCfg.compression = pVnodeCfg->cfg.compression;;
|
||||
|
||||
|
||||
char tsdbDir[TSDB_FILENAME_LEN] = {0};
|
||||
sprintf(tsdbDir, "%s/vnode%d/tsdb", tsVnodeDir, pVnodeCfg->cfg.vgId);
|
||||
code = tsdbCreateRepo(tsdbDir, &tsdbCfg, NULL);
|
||||
|
@ -139,7 +141,7 @@ int32_t vnodeDrop(int32_t vgId) {
|
|||
vTrace("vgId:%d, vnode will be dropped", pVnode->vgId);
|
||||
pVnode->status = TAOS_VN_STATUS_DELETING;
|
||||
vnodeCleanUp(pVnode);
|
||||
|
||||
|
||||
return TSDB_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -262,7 +264,7 @@ int32_t vnodeOpen(int32_t vnode, char *rootDir) {
|
|||
#endif
|
||||
|
||||
// start continuous query
|
||||
if (pVnode->role == TAOS_SYNC_ROLE_MASTER)
|
||||
if (pVnode->role == TAOS_SYNC_ROLE_MASTER)
|
||||
cqStart(pVnode->cq);
|
||||
|
||||
pVnode->events = NULL;
|
||||
|
@ -342,7 +344,7 @@ void *vnodeAccquireVnode(int32_t vgId) {
|
|||
}
|
||||
|
||||
void *vnodeGetRqueue(void *pVnode) {
|
||||
return ((SVnodeObj *)pVnode)->rqueue;
|
||||
return ((SVnodeObj *)pVnode)->rqueue;
|
||||
}
|
||||
|
||||
void *vnodeGetWqueue(int32_t vgId) {
|
||||
|
@ -352,7 +354,7 @@ void *vnodeGetWqueue(int32_t vgId) {
|
|||
}
|
||||
|
||||
void *vnodeGetWal(void *pVnode) {
|
||||
return ((SVnodeObj *)pVnode)->wal;
|
||||
return ((SVnodeObj *)pVnode)->wal;
|
||||
}
|
||||
|
||||
static void vnodeBuildVloadMsg(SVnodeObj *pVnode, SDMStatusMsg *pStatus) {
|
||||
|
@ -447,9 +449,9 @@ static void vnodeNotifyRole(void *ahandle, int8_t role) {
|
|||
vPrint("vgId:%d, sync role changed from %d to %d", pVnode->vgId, pVnode->role, role);
|
||||
pVnode->role = role;
|
||||
|
||||
if (pVnode->role == TAOS_SYNC_ROLE_MASTER)
|
||||
if (pVnode->role == TAOS_SYNC_ROLE_MASTER)
|
||||
cqStart(pVnode->cq);
|
||||
else
|
||||
else
|
||||
cqStop(pVnode->cq);
|
||||
}
|
||||
|
||||
|
@ -488,6 +490,10 @@ static int32_t vnodeSaveCfg(SMDCreateVnodeMsg *pVnodeCfg) {
|
|||
int32_t len = 0;
|
||||
int32_t maxLen = 1000;
|
||||
char * content = calloc(1, maxLen + 1);
|
||||
if (content == NULL) {
|
||||
fclose(fp);
|
||||
return TSDB_CODE_NO_RESOURCE;
|
||||
}
|
||||
|
||||
len += snprintf(content + len, maxLen - len, "{\n");
|
||||
|
||||
|
@ -501,14 +507,14 @@ static int32_t vnodeSaveCfg(SMDCreateVnodeMsg *pVnodeCfg) {
|
|||
len += snprintf(content + len, maxLen - len, " \"daysToKeep2\": %d,\n", pVnodeCfg->cfg.daysToKeep2);
|
||||
len += snprintf(content + len, maxLen - len, " \"minRowsPerFileBlock\": %d,\n", pVnodeCfg->cfg.minRowsPerFileBlock);
|
||||
len += snprintf(content + len, maxLen - len, " \"maxRowsPerFileBlock\": %d,\n", pVnodeCfg->cfg.maxRowsPerFileBlock);
|
||||
len += snprintf(content + len, maxLen - len, " \"commitTime\": %d,\n", pVnodeCfg->cfg.commitTime);
|
||||
len += snprintf(content + len, maxLen - len, " \"commitTime\": %d,\n", pVnodeCfg->cfg.commitTime);
|
||||
len += snprintf(content + len, maxLen - len, " \"precision\": %d,\n", pVnodeCfg->cfg.precision);
|
||||
len += snprintf(content + len, maxLen - len, " \"compression\": %d,\n", pVnodeCfg->cfg.compression);
|
||||
len += snprintf(content + len, maxLen - len, " \"walLevel\": %d,\n", pVnodeCfg->cfg.walLevel);
|
||||
len += snprintf(content + len, maxLen - len, " \"replica\": %d,\n", pVnodeCfg->cfg.replications);
|
||||
len += snprintf(content + len, maxLen - len, " \"wals\": %d,\n", pVnodeCfg->cfg.wals);
|
||||
len += snprintf(content + len, maxLen - len, " \"quorum\": %d,\n", pVnodeCfg->cfg.quorum);
|
||||
|
||||
|
||||
len += snprintf(content + len, maxLen - len, " \"nodeInfos\": [{\n");
|
||||
for (int32_t i = 0; i < pVnodeCfg->cfg.replications; i++) {
|
||||
len += snprintf(content + len, maxLen - len, " \"nodeId\": %d,\n", pVnodeCfg->nodes[i].nodeId);
|
||||
|
@ -528,7 +534,7 @@ static int32_t vnodeSaveCfg(SMDCreateVnodeMsg *pVnodeCfg) {
|
|||
|
||||
vPrint("vgId:%d, save vnode cfg successed", pVnodeCfg->cfg.vgId);
|
||||
|
||||
return 0;
|
||||
return TSDB_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
static int32_t vnodeReadCfg(SVnodeObj *pVnode) {
|
||||
|
@ -552,6 +558,7 @@ static int32_t vnodeReadCfg(SVnodeObj *pVnode) {
|
|||
int len = fread(content, 1, maxLen, fp);
|
||||
if (len <= 0) {
|
||||
vError("vgId:%d, failed to read vnode cfg, content is null", pVnode->vgId);
|
||||
free(content);
|
||||
return errno;
|
||||
}
|
||||
|
||||
|
@ -741,7 +748,7 @@ static int32_t vnodeSaveVersion(SVnodeObj *pVnode) {
|
|||
|
||||
int32_t len = 0;
|
||||
int32_t maxLen = 30;
|
||||
char * content = calloc(1, maxLen + 1);
|
||||
char content[TSDB_VNODE_VERSION_CONTENT_LEN] = {0};
|
||||
|
||||
len += snprintf(content + len, maxLen - len, "{\n");
|
||||
len += snprintf(content + len, maxLen - len, " \"version\": %" PRId64 "\n", pVnode->fversion);
|
||||
|
@ -749,11 +756,10 @@ static int32_t vnodeSaveVersion(SVnodeObj *pVnode) {
|
|||
|
||||
fwrite(content, 1, len, fp);
|
||||
fclose(fp);
|
||||
free(content);
|
||||
|
||||
vPrint("vgId:%d, save vnode version:%" PRId64 " succeed", pVnode->vgId, pVnode->fversion);
|
||||
|
||||
return 0;
|
||||
return TSDB_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
static int32_t vnodeReadVersion(SVnodeObj *pVnode) {
|
||||
|
|
|
@ -39,8 +39,8 @@ void vnodeInitReadFp(void) {
|
|||
int32_t vnodeProcessRead(void *param, int msgType, void *pCont, int32_t contLen, SRspRet *ret) {
|
||||
SVnodeObj *pVnode = (SVnodeObj *)param;
|
||||
|
||||
if (vnodeProcessReadMsgFp[msgType] == NULL)
|
||||
return TSDB_CODE_MSG_NOT_PROCESSED;
|
||||
if (vnodeProcessReadMsgFp[msgType] == NULL)
|
||||
return TSDB_CODE_MSG_NOT_PROCESSED;
|
||||
|
||||
if (pVnode->status == TAOS_VN_STATUS_DELETING || pVnode->status == TAOS_VN_STATUS_CLOSING)
|
||||
return TSDB_CODE_INVALID_VGROUP_ID;
|
||||
|
@ -53,26 +53,29 @@ static int32_t vnodeProcessQueryMsg(SVnodeObj *pVnode, void *pCont, int32_t cont
|
|||
memset(pRet, 0, sizeof(SRspRet));
|
||||
|
||||
int32_t code = TSDB_CODE_SUCCESS;
|
||||
|
||||
|
||||
qinfo_t pQInfo = NULL;
|
||||
if (contLen != 0) {
|
||||
pRet->code = qCreateQueryInfo(pVnode->tsdb, pVnode->vgId, pQueryTableMsg, &pQInfo);
|
||||
|
||||
|
||||
SQueryTableRsp *pRsp = (SQueryTableRsp *) rpcMallocCont(sizeof(SQueryTableRsp));
|
||||
pRsp->qhandle = htobe64((uint64_t) (pQInfo));
|
||||
pRsp->code = pRet->code;
|
||||
|
||||
|
||||
pRet->len = sizeof(SQueryTableRsp);
|
||||
pRet->rsp = pRsp;
|
||||
|
||||
vTrace("vgId:%d, QInfo:%p, dnode query msg disposed", pVnode->vgId, pQInfo);
|
||||
} else {
|
||||
assert(pCont != NULL);
|
||||
pQInfo = pCont;
|
||||
code = TSDB_CODE_ACTION_IN_PROGRESS;
|
||||
}
|
||||
|
||||
qTableQuery(pQInfo); // do execute query
|
||||
|
||||
if (pQInfo != NULL) {
|
||||
qTableQuery(pQInfo); // do execute query
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
|
|
|
@ -104,67 +104,14 @@ static int32_t vnodeProcessSubmitMsg(SVnodeObj *pVnode, void *pCont, SRspRet *pR
|
|||
}
|
||||
|
||||
static int32_t vnodeProcessCreateTableMsg(SVnodeObj *pVnode, void *pCont, SRspRet *pRet) {
|
||||
SMDCreateTableMsg *pTable = pCont;
|
||||
int32_t code = 0;
|
||||
|
||||
vTrace("vgId:%d, table:%s, start to create", pVnode->vgId, pTable->tableId);
|
||||
int16_t numOfColumns = htons(pTable->numOfColumns);
|
||||
int16_t numOfTags = htons(pTable->numOfTags);
|
||||
int32_t sid = htonl(pTable->sid);
|
||||
uint64_t uid = htobe64(pTable->uid);
|
||||
SSchema * pSchema = (SSchema *)pTable->data;
|
||||
STSchema *pDestTagSchema = NULL;
|
||||
SDataRow dataRow = NULL;
|
||||
|
||||
int32_t totalCols = numOfColumns + numOfTags;
|
||||
|
||||
STableCfg tCfg;
|
||||
tsdbInitTableCfg(&tCfg, pTable->tableType, uid, sid);
|
||||
STableCfg *pCfg = tsdbCreateTableCfgFromMsg((SMDCreateTableMsg *)pCont);
|
||||
if (pCfg == NULL) return terrno;
|
||||
int32_t code = tsdbCreateTable(pVnode->tsdb, pCfg);
|
||||
|
||||
STSchema *pDestSchema = tdNewSchema(numOfColumns);
|
||||
for (int i = 0; i < numOfColumns; i++) {
|
||||
tdSchemaAddCol(pDestSchema, pSchema[i].type, htons(pSchema[i].colId), htons(pSchema[i].bytes));
|
||||
}
|
||||
tsdbTableSetSchema(&tCfg, pDestSchema, false);
|
||||
tsdbTableSetName(&tCfg, pTable->tableId, false);
|
||||
|
||||
if (numOfTags != 0) {
|
||||
pDestTagSchema = tdNewSchema(numOfTags);
|
||||
for (int i = numOfColumns; i < totalCols; i++) {
|
||||
tdSchemaAddCol(pDestTagSchema, pSchema[i].type, htons(pSchema[i].colId), htons(pSchema[i].bytes));
|
||||
}
|
||||
tsdbTableSetTagSchema(&tCfg, pDestTagSchema, false);
|
||||
tsdbTableSetSName(&tCfg, pTable->superTableId, false);
|
||||
tsdbTableSetSuperUid(&tCfg, htobe64(pTable->superTableUid));
|
||||
|
||||
char *pTagData = pTable->data + totalCols * sizeof(SSchema);
|
||||
int accumBytes = 0;
|
||||
//dataRow = tdNewDataRowFromSchema(pDestTagSchema);
|
||||
dataRow = tdNewTagRowFromSchema(pDestTagSchema, numOfTags);
|
||||
|
||||
for (int i = 0; i < numOfTags; i++) {
|
||||
STColumn *pTCol = schemaColAt(pDestTagSchema, i);
|
||||
// tdAppendColVal(dataRow, pTagData + accumBytes, pTCol->type, pTCol->bytes, pTCol->offset);
|
||||
tdAppendTagColVal(dataRow, pTagData + accumBytes, pTCol->type, pTCol->bytes, pTCol->colId);
|
||||
accumBytes += htons(pSchema[i + numOfColumns].bytes);
|
||||
}
|
||||
tsdbTableSetTagValue(&tCfg, dataRow, false);
|
||||
}
|
||||
|
||||
// only normal has sql string
|
||||
if (pTable->tableType == TSDB_STREAM_TABLE) {
|
||||
char *sql = pTable->data + totalCols * sizeof(SSchema);
|
||||
vTrace("vgId:%d, table:%s is creating, sql:%s", pVnode->vgId, pTable->tableId, sql);
|
||||
tsdbTableSetStreamSql(&tCfg, sql, false);
|
||||
}
|
||||
|
||||
code = tsdbCreateTable(pVnode->tsdb, &tCfg);
|
||||
tdFreeDataRow(dataRow);
|
||||
tfree(pDestTagSchema);
|
||||
tfree(pDestSchema);
|
||||
|
||||
vTrace("vgId:%d, table:%s is created, result:%x", pVnode->vgId, pTable->tableId, code);
|
||||
return code;
|
||||
tsdbClearTableCfg(pCfg);
|
||||
free(pCfg);
|
||||
return code;
|
||||
}
|
||||
|
||||
static int32_t vnodeProcessDropTableMsg(SVnodeObj *pVnode, void *pCont, SRspRet *pRet) {
|
||||
|
@ -183,52 +130,11 @@ static int32_t vnodeProcessDropTableMsg(SVnodeObj *pVnode, void *pCont, SRspRet
|
|||
}
|
||||
|
||||
static int32_t vnodeProcessAlterTableMsg(SVnodeObj *pVnode, void *pCont, SRspRet *pRet) {
|
||||
SMDCreateTableMsg *pTable = pCont;
|
||||
int32_t code = 0;
|
||||
|
||||
vTrace("vgId:%d, table:%s, start to alter", pVnode->vgId, pTable->tableId);
|
||||
int16_t numOfColumns = htons(pTable->numOfColumns);
|
||||
int16_t numOfTags = htons(pTable->numOfTags);
|
||||
int32_t sid = htonl(pTable->sid);
|
||||
uint64_t uid = htobe64(pTable->uid);
|
||||
SSchema *pSchema = (SSchema *) pTable->data;
|
||||
|
||||
int32_t totalCols = numOfColumns + numOfTags;
|
||||
|
||||
STableCfg tCfg;
|
||||
tsdbInitTableCfg(&tCfg, pTable->tableType, uid, sid);
|
||||
|
||||
STSchema *pDestSchema = tdNewSchema(numOfColumns);
|
||||
for (int i = 0; i < numOfColumns; i++) {
|
||||
tdSchemaAddCol(pDestSchema, pSchema[i].type, htons(pSchema[i].colId), htons(pSchema[i].bytes));
|
||||
}
|
||||
tsdbTableSetSchema(&tCfg, pDestSchema, false);
|
||||
|
||||
if (numOfTags != 0) {
|
||||
STSchema *pDestTagSchema = tdNewSchema(numOfTags);
|
||||
for (int i = numOfColumns; i < totalCols; i++) {
|
||||
tdSchemaAddCol(pDestTagSchema, pSchema[i].type, htons(pSchema[i].colId), htons(pSchema[i].bytes));
|
||||
}
|
||||
tsdbTableSetTagSchema(&tCfg, pDestTagSchema, false);
|
||||
|
||||
char *pTagData = pTable->data + totalCols * sizeof(SSchema);
|
||||
int accumBytes = 0;
|
||||
SDataRow dataRow = tdNewDataRowFromSchema(pDestTagSchema);
|
||||
|
||||
for (int i = 0; i < numOfTags; i++) {
|
||||
STColumn *pTCol = schemaColAt(pDestTagSchema, i);
|
||||
tdAppendColVal(dataRow, pTagData + accumBytes, pTCol->type, pTCol->bytes, pTCol->offset);
|
||||
accumBytes += htons(pSchema[i + numOfColumns].bytes);
|
||||
}
|
||||
tsdbTableSetTagValue(&tCfg, dataRow, false);
|
||||
}
|
||||
|
||||
code = tsdbAlterTable(pVnode->tsdb, &tCfg);
|
||||
|
||||
tfree(pDestSchema);
|
||||
|
||||
vTrace("vgId:%d, table:%s, alter table result:%d", pVnode->vgId, pTable->tableId, code);
|
||||
|
||||
STableCfg *pCfg = tsdbCreateTableCfgFromMsg((SMDCreateTableMsg *)pCont);
|
||||
if (pCfg == NULL) return terrno;
|
||||
int32_t code = tsdbAlterTable(pVnode->tsdb, pCfg);
|
||||
tsdbClearTableCfg(pCfg);
|
||||
free(pCfg);
|
||||
return code;
|
||||
}
|
||||
|
||||
|
|
|
@ -8,8 +8,8 @@
|
|||
|
||||
3. mkdir debug; cd debug; cmake ..; make ; sudo make install
|
||||
|
||||
4. pip install src/connector/python/linux/python2 ; pip3 install
|
||||
src/connector/python/linux/python3
|
||||
4. pip install ../src/connector/python/linux/python2 ; pip3 install
|
||||
../src/connector/python/linux/python3
|
||||
|
||||
> Note: Both Python2 and Python3 are currently supported by the Python test
|
||||
> framework. Since Python2 is no longer officially supported by Python Software
|
||||
|
|
|
@ -16,11 +16,12 @@
|
|||
// TAOS standard API example. The same syntax as MySQL, but only a subet
|
||||
// to compile: gcc -o demo demo.c -ltaos
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <taos.h> // TAOS header file
|
||||
#include <unistd.h>
|
||||
|
||||
void taosMsleep(int mseconds);
|
||||
|
||||
|
@ -49,19 +50,52 @@ static int32_t doQuery(TAOS* taos, const char* sql) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
void* oneLoader(void* param) {
|
||||
TAOS* conn = (TAOS*) param;
|
||||
|
||||
for(int32_t i = 0; i < 20000; ++i) {
|
||||
// doQuery(conn, "show databases");
|
||||
doQuery(conn, "use test");
|
||||
// doQuery(conn, "describe t12");
|
||||
// doQuery(conn, "show tables");
|
||||
// doQuery(conn, "create table if not exists abc (ts timestamp, k int)");
|
||||
// doQuery(conn, "select * from t12");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static __attribute__((unused)) void multiThreadTest(int32_t numOfThreads, void* conn) {
|
||||
pthread_attr_t thattr;
|
||||
pthread_attr_init(&thattr);
|
||||
pthread_attr_setdetachstate(&thattr, PTHREAD_CREATE_JOINABLE);
|
||||
|
||||
pthread_t* threadId = malloc(sizeof(pthread_t)*numOfThreads);
|
||||
|
||||
for (int i = 0; i < numOfThreads; ++i) {
|
||||
pthread_create(&threadId[i], NULL, oneLoader, conn);
|
||||
}
|
||||
|
||||
for (int32_t i = 0; i < numOfThreads; ++i) {
|
||||
pthread_join(threadId[i], NULL);
|
||||
}
|
||||
|
||||
pthread_attr_destroy(&thattr);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
TAOS * taos;
|
||||
char qstr[1024];
|
||||
TAOS_RES *result;
|
||||
|
||||
|
||||
// connect to server
|
||||
if (argc < 2) {
|
||||
printf("please input server-ip \n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
taos_options(TSDB_OPTION_CONFIGDIR, "~/sec/cfg");
|
||||
taos_options(TSDB_OPTION_CONFIGDIR, "/home/lisa/Documents/workspace/TDinternal/community/sim/tsim/cfg");
|
||||
|
||||
// init TAOS
|
||||
taos_init();
|
||||
|
@ -73,15 +107,12 @@ int main(int argc, char *argv[]) {
|
|||
}
|
||||
printf("success to connect to server\n");
|
||||
|
||||
doQuery(taos, "create database if not exists test");
|
||||
doQuery(taos, "use test");
|
||||
doQuery(taos, "select count(*) from m1 where ts>='2020-1-1 1:1:1' and ts<='2020-1-1 1:1:59' interval(500a) fill(value, 99)");
|
||||
|
||||
// doQuery(taos, "create table t1(ts timestamp, k binary(12), f nchar(2))");
|
||||
// for(int32_t i = 0; i< 100000; ++i) {
|
||||
// doQuery(taos, "select m1.ts,m1.a from m1, m2 where m1.ts=m2.ts and m1.a=m2.b;");
|
||||
// usleep(500000);
|
||||
// multiThreadTest(1, taos);
|
||||
doQuery(taos, "select max(c1), min(c2), sum(c3), avg(c4), first(c7), last(c8), first(c9) from lm2_db0.lm2_stb0 where ts >= 1537146000000 and ts <= 1543145400000 interval(5m) fill(value, -1, -2) group by t1 limit 2 offset 10;");
|
||||
// for(int32_t i = 0; i < 100000; ++i) {
|
||||
// doQuery(taos, "insert into t1 values(now, 2)");
|
||||
// }
|
||||
// doQuery(taos, "create table t1(ts timestamp, k binary(12), f nchar(2))");
|
||||
|
||||
// doQuery(taos, "insert into tm0 values('2020-1-1 1:1:1', 'abc')");
|
||||
// doQuery(taos, "create table if not exists tm0 (ts timestamp, k int);");
|
||||
|
|
|
@ -31,12 +31,26 @@ function collectSysInfo {
|
|||
|
||||
function buildTDengine {
|
||||
cd /root/TDengine
|
||||
git pull
|
||||
cd debug
|
||||
rm -rf *
|
||||
cmake ..
|
||||
make > /dev/null
|
||||
make install
|
||||
|
||||
git remote update
|
||||
REMOTE_COMMIT=`git rev-parse --short remotes/origin/develop`
|
||||
LOCAL_COMMIT=`git rev-parse --short @`
|
||||
|
||||
echo " LOCAL: $LOCAL_COMMIT"
|
||||
echo "REMOTE: $REMOTE_COMMIT"
|
||||
if [ "$LOCAL_COMMIT" == "$REMOTE_COMMIT" ]; then
|
||||
echo "repo up-to-date"
|
||||
else
|
||||
echo "repo need to pull"
|
||||
git pull
|
||||
|
||||
LOCAL_COMMIT=`git rev-parse --short @`
|
||||
cd debug
|
||||
rm -rf *
|
||||
cmake ..
|
||||
make > /dev/null
|
||||
make install
|
||||
fi
|
||||
}
|
||||
|
||||
function restartTaosd {
|
||||
|
@ -55,7 +69,7 @@ function sendReport {
|
|||
receiver="sdsang@taosdata.com, sangshuduo@gmail.com"
|
||||
mimebody="MIME-Version: 1.0\nContent-Type: text/html; charset=utf-8\n"
|
||||
|
||||
echo -e "to: ${receiver}\nsubject: Perf test report ${today}\n" | \
|
||||
echo -e "to: ${receiver}\nsubject: Perf test report ${today}, commit ID: ${LOCAL_COMMIT}\n" | \
|
||||
(cat - && uuencode perftest-1d-$today.log perftest-1d-$today.log)| \
|
||||
(cat - && uuencode perftest-1d-report.csv perftest-1d-report-$today.csv) | \
|
||||
(cat - && uuencode perftest-1d-report.png perftest-1d-report-$today.png) | \
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
#!/bin/bash
|
||||
ulimit -c unlimited
|
||||
|
||||
python3 ./test.py -f insert/basic.py
|
||||
python3 ./test.py -f insert/int.py
|
||||
python3 ./test.py -f insert/float.py
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
#!/bin/bash
|
||||
ulimit -c unlimited
|
||||
|
||||
# insert
|
||||
python3 ./test.py $1 -f insert/basic.py
|
||||
python3 ./test.py $1 -s && sleep 1
|
||||
|
@ -56,10 +58,4 @@ python3 ./test.py $1 -s && sleep 1
|
|||
#query
|
||||
python3 ./test.py $1 -f query/filter.py
|
||||
python3 ./test.py $1 -s && sleep 1
|
||||
python3 ./test.py $1 -f query/filterCombo.py
|
||||
python3 ./test.py $1 -s && sleep 1
|
||||
python3 ./test.py $1 -f query/queryNormal.py
|
||||
python3 ./test.py $1 -s && sleep 1
|
||||
python3 ./test.py $1 -f query/queryError.py
|
||||
python3 ./test.py $1 -s && sleep 1
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue